gpt4 book ai didi

scala - Cats 效应和异步 IO 细节

转载 作者:行者123 更新时间:2023-12-03 03:27:59 30 4
gpt4 key购买 nike

几天来,我一直在关注猫效应和 IO。我觉得我对这种效果有一些误解,或者只是我错过了它的重点。

  • 首先——如果IO可以替代Scala的Future,我们如何创建异步IO任务?使用 IO.shift ?使用 IO.async ?是 IO.delay同步还是异步?我们可以用这样的代码来做一个通用的异步任务 Async[F].delay(...) ?或者当我们使用 unsafeToAsync 调用 IO 时发生异步或 unsafeToFuture ?
  • 猫效应中异步和并发的意义是什么?他们为什么分开?
  • IO 是绿线吗?如果是,为什么cats-effect中有一个Fiber对象?据我所知,Fiber 是绿色线程,但文档声称我们可以将 IO 视为绿色线程。

  • 我希望能对此进行一些澄清,因为我未能理解这些中的猫效应文档,而互联网并没有那么有帮助......

    最佳答案

    if IO can replace Scala's Future, how can we create an async IO task



    首先,我们需要澄清什么是异步任务。通常 async 的意思是“不阻塞操作系统线程”,但既然你提到了 Future ,有点糊。说,如果我写:
    Future { (1 to 1000000).foreach(println) }

    它不会是异步的,因为它是一个阻塞循环和阻塞输出,但它可能会在不同的操作系统线程上执行,由隐式 ExecutionContext 管理。等效的猫效应代码是:
    for {
    _ <- IO.shift
    _ <- IO.delay { (1 to 1000000).foreach(println) }
    } yield ()

    (这不是较短的版本)

    所以,
  • IO.shift用于可能更改线程/线程池。 Future在每个操作上都这样做,但它在性能方面不是免费的。
  • IO.delay { ... } (a.k.a. IO { ... } ) 不会使任何异步并且不会切换线程。它用于创建简单的 IO来自同步副作用 API 的值


  • 现在,让我们回到真正的异步。这里要理解的是:

    每个异步计算都可以表示为一个接受回调的函数。

    是否使用返回 Future 的 API或 Java 的 CompletableFuture ,或类似 NIO CompletionHandler ,这一切都可以转换为回调。这是什么 IO.async用于:您可以转换任何 函数采用回调 IO .在这种情况下:
    for {
    _ <- IO.async { ... }
    _ <- IO(println("Done"))
    } yield ()
    Done将仅在 ... 中的计算时(以及如果)打印回电。您可以将其视为阻塞绿色线程,而不是 OS 线程。

    所以,
  • IO.async用于将任何已经异步的计算转换为 IO .
  • IO.delay用于将任何完全同步的计算转换为 IO .
  • 具有真正异步计算的代码就像阻塞了一个绿色线程。

  • 使用 Future 时最接近的类比s 正在创建 scala.concurrent.Promise并返回 p.future .

    Or async happens when we call IO with unsafeToAsync or unsafeToFuture?



    有点。与 IO ,除非您调用其中之一(或使用 IOApp ),否则不会发生任何事情。但是 IO 并不能保证你会在不同的操作系统线程上执行,甚至异步执行,除非你用 IO.shift 明确要求这样做。或 IO.async .

    您可以保证线程随时切换,例如 (IO.shift *> myIO).unsafeRunAsyncAndForget() .这是可能的,正是因为 myIO在被要求之前不会被执行,无论你是否拥有它 val myIOdef myIO .

    但是,您不能神奇地将阻塞操作转换为非阻塞操作。 Future 也不可能做到这一点也不与 IO .

    What's the point of Async and Concurrent in cats-effect? Why they are separated?


    AsyncConcurrent (和 Sync )是类型类。它们的设计是为了让程序员可以避免被锁定到 cats.effect.IO并且可以为您提供支持您选择的任何 API 的 API,例如 monix Task 或 Scalaz 8 ZIO,甚至 monad 转换器类型,例如 OptionT[Task, *something*] .诸如 fs2、monix 和 http4s 之类的库使用它们来为您提供更多选择来使用它们。
    ConcurrentAsync 之上添加额外的东西,其中最重要的是 .cancelable.start .这些与 Future 没有直接的类比。 ,因为那根本不支持取消。
    .cancelable.async的一个版本这还允许您指定一些逻辑来取消您正在包装的操作。一个常见的例子是网络请求 - 如果您不再对结果感兴趣,您可以中止它们而无需等待服务器响应,并且不会在读取响应时浪费任何套接字或处理时间。你可能永远不会直接使用它,但它有它的地方。

    但是如果你不能取消它们,可取消的操作又有什么用呢?这里的关键观察是您不能从其内部取消操作。其他人必须做出这个决定,这将与操作本身同时发生(这是类型类的名称所在)。那就是 .start进来。简而言之,

    .start是一个绿色线程的显式分支。

    someIO.start类似于做 val t = new Thread(someRunnable); t.start() ,除了它现在是绿色的。和 Fiber本质上是 Thread 的精简版API:你可以做 .join ,就像 Thread#join() ,但它不会阻塞操作系统线程;和 .cancel ,这是 .interrupt() 的安全版本.

    请注意,还有其他方法可以 fork 绿色线程。例如,做并行操作:
    val ids: List[Int] = List.range(1, 1000)
    def processId(id: Int): IO[Unit] = ???
    val processAll: IO[Unit] = ids.parTraverse_(processId)

    将 fork 处理所有 ID 为绿色线程,然后将它们全部加入。或使用 .race :
    val fetchFromS3: IO[String] = ???
    val fetchFromOtherNode: IO[String] = ???

    val fetchWhateverIsFaster = IO.race(fetchFromS3, fetchFromOtherNode).map(_.merge)

    将并行执行提取,为您提供完成的第一个结果并自动取消较慢的提取。所以,做 .start并使用 Fiber不是 fork 更多绿色线程的唯一方法,只是最明确的方法。答案是:

    Is IO a green thread? If yes, why is there a Fiber object in cats-effect? As I understand the Fiber is the green thread, but docs claim we can think of IOs as green threads.


  • IO就像一个绿色线程,这意味着您可以在没有操作系统线程开销的情况下并行运行许多它们,并且 for-comprehension 中的代码表现得好像它正在阻塞要计算的结果。
  • Fiber是一个用于控制绿色线程显式 fork (等待完成或取消)的工具。
  • 关于scala - Cats 效应和异步 IO 细节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53682686/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com