简体   繁体   English

Scala Cats效果 - IO异步转换 - 它是如何工作的?

[英]Scala Cats Effects - IO Async Shift - How Does it Work?

Here is some Scala cats code using the IO Monad : 以下是使用IO Monad的一些Scala猫代码:

import java.util.concurrent.{ExecutorService, Executors}

import cats.effect.IO

import scala.concurrent.{ExecutionContext, ExecutionContextExecutor}
import scala.util.control.NonFatal

object Program extends App {

  type CallbackType = (Either[Throwable, Unit]) => Unit

  // IO.async[Unit] is like a Future that returns Unit on completion.
  // Unlike a regular Future, it doesn't start to run until unsafeRunSync is called.
  def forkAsync(toRun: () => Unit)(executor: ExecutorService): IO[Unit] = IO.async[Unit] { callback: CallbackType =>
    // "callback" is a function that either takes a throwable (Left) or whatever toRun returns (Right).
    println("LalalaAsync: " + Thread.currentThread().getName)
    executor.execute(new Runnable {
      def run(): Unit = {
        val nothing: Unit = toRun() // Note: This line executes the body and returns nothing, which is of type Unit.
        try {
          callback(Right(nothing)) // On success, the callback returns nothing
        } catch {
          case NonFatal(t) => callback(Left(t)) // On failure, it returns an exception
        }
      }
    })
  }

  def forkSync(toRun: () => Unit)(executor: ExecutorService): IO[Unit] = IO.apply {
    println("LalalaSync: " + Thread.currentThread().getName)
    executor.execute(new Runnable {
      def run(): Unit = {
        toRun()
      }
    })
  }

  val treadPool: ExecutorService = Executors.newSingleThreadExecutor()
  val mainThread: Thread = Thread.currentThread()

  val Global: ExecutionContextExecutor = ExecutionContext.global

  /*
  Output:
    1 Hello World printed synchronously from Main.main
    LalalaSync: scala-execution-context-global-12
    Hello World printed synchronously from thread pool.pool-1-thread-1
    LalalaAsync: scala-execution-context-global-12
    Hello World printed asynchronously from thread pool.pool-1-thread-1
    2 Hello World printed synchronously from Global .scala-execution-context-global-12
   */
  val program = for {
    _ <- IO {
      println("1 Hello World printed synchronously from Main." + Thread.currentThread().getName) // "main" thread
    }
    _ <- IO.shift(Global) // Shift to Global Execution Context
    _ <- forkSync { () =>
      println("Hello World printed synchronously from thread pool." + Thread.currentThread().getName) // "pool-1-thread-1" thread
    }(treadPool)
    _ <- forkAsync { () =>
      println("Hello World printed asynchronously from thread pool." + Thread.currentThread().getName) // "pool-1-thread-1" thread
    }(treadPool)
    _ <- IO.shift(Global) // Shift to Global Execution Context
    _ <- IO {
      println("2 Hello World printed synchronously from Global ." + Thread.currentThread().getName) // "scala-execution-context-global-13" thread
    }
  } yield ()

  program.unsafeRunSync()
}

To run it you would need to add: 要运行它,您需要添加:

libraryDependencies ++= Seq(
  "org.typelevel" %% "cats" % "0.9.0",
  "org.typelevel" %% "cats-effect" % "0.3"
),

To your build.sbt file. 到你的build.sbt文件。

Note the output: 注意输出:

  /*
  Output:
    1 Hello World printed synchronously from Main.main
    LalalaSync: scala-execution-context-global-12
    Hello World printed synchronously from thread pool.pool-1-thread-1
    LalalaAsync: scala-execution-context-global-12
    Hello World printed asynchronously from thread pool.pool-1-thread-1
    2 Hello World printed synchronously from Global .scala-execution-context-global-12
 */

Basically, I don't understand how IO.shift(Global) or how IO.async works. 基本上,我不明白IO.shift(全局)或IO.async如何工作。

For example, why is it that after I call "forkAsync", if I don't call "IO.shift(Global)", the subsequent synchronous IO objects are run in "pool-1-thread-1". 例如,为什么在我调用“forkAsync”之后,如果我不调用“IO.shift(Global)”,则后续的同步IO对象将在“pool-1-thread-1”中运行。 Also, what is the difference between forkAsync and forkSync in this example? 另外,在这个例子中,forkAsync和forkSync有什么区别? Both of them start in the ExecutionContext.global and then execute a Runnable in "pool.pool-1-thread-1". 它们都在ExecutionContext.global中启动,然后在“pool.pool-1-thread-1”中执行Runnable。

Like are forkAsync and forkSync doing the exact same thing or is forkAsync doing something different? 就像forkAsync和forkSync做同样的事情或者forkAsync做一些不同的事情? If they are doing the same thing, what is the point of wrapping code in IO.async? 如果他们正在做同样的事情,那么在IO.async中包装代码有什么意义呢? If they are not doing the same thing, how are they different? 如果他们没有做同样的事情,他们有什么不同?

For example, why is it that after I call "forkAsync", if I don't call "IO.shift(Global)", the subsequent synchronous IO objects are run in "pool-1-thread-1". 例如,为什么在我调用“forkAsync”之后,如果我不调用“IO.shift(Global)”,则后续的同步IO对象将在“pool-1-thread-1”中运行。

The more important question is why would you expect it to evaluate the "subsequent synchronous IO objects" on global? 更重要的问题是为什么你期望它评估全球的“后续同步IO对象”?

IO doesn't have internally the notion of thread-pools, it doesn't know about global , so it cannot shift back to your default thread-pool, therefore you need to trigger a manual shift indeed. IO内部没有线程池的概念,它不了解global ,因此它无法转移回默认的线程池,因此您需要触发手动转换。

Upgrade to the latest version 1.0.0 and you also have evalOn in ContextShift which will execute an IO action on a specified thread-pool and then shift back to your "global", which I suppose is what you want. 升级到最新版本1.0.0 ,你还在ContextShift中有evalOn ,它将在指定的线程池上执行IO操作,然后切换回你的“全局”,我想这就是你想要的。

Also, what is the difference between forkAsync and forkSync in this example? 另外,在这个例子中,forkAsync和forkSync有什么区别?

Your forkSync triggers the execution of the Runnable , but does not wait for its completion. forkSync触发Runnable的执行,但不等待其完成。 It's a fire and forget. 这是一场火灾,忘记了。 Which means that subsequent chained actions will not do back-pressuring. 这意味着后续的链式操作不会进行反压。

Some advice: 一些忠告:

  1. upgrade to the latest version ( 1.0.0 ) 升级到最新版本( 1.0.0
  2. read the docs at: https://typelevel.org/cats-effect/datatypes/io.html 阅读文档: https//typelevel.org/cats-effect/datatypes/io.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM