簡體   English   中英

Scala Cats效果 - IO異步轉換 - 它是如何工作的?

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

以下是使用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()
}

要運行它,您需要添加:

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

到你的build.sbt文件。

注意輸出:

  /*
  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
 */

基本上,我不明白IO.shift(全局)或IO.async如何工作。

例如,為什么在我調用“forkAsync”之后,如果我不調用“IO.shift(Global)”,則后續的同步IO對象將在“pool-1-thread-1”中運行。 另外,在這個例子中,forkAsync和forkSync有什么區別? 它們都在ExecutionContext.global中啟動,然后在“pool.pool-1-thread-1”中執行Runnable。

就像forkAsync和forkSync做同樣的事情或者forkAsync做一些不同的事情? 如果他們正在做同樣的事情,那么在IO.async中包裝代碼有什么意義呢? 如果他們沒有做同樣的事情,他們有什么不同?

例如,為什么在我調用“forkAsync”之后,如果我不調用“IO.shift(Global)”,則后續的同步IO對象將在“pool-1-thread-1”中運行。

更重要的問題是為什么你期望它評估全球的“后續同步IO對象”?

IO內部沒有線程池的概念,它不了解global ,因此它無法轉移回默認的線程池,因此您需要觸發手動轉換。

升級到最新版本1.0.0 ,你還在ContextShift中有evalOn ,它將在指定的線程池上執行IO操作,然后切換回你的“全局”,我想這就是你想要的。

另外,在這個例子中,forkAsync和forkSync有什么區別?

forkSync觸發Runnable的執行,但不等待其完成。 這是一場火災,忘記了。 這意味着后續的鏈式操作不會進行反壓。

一些忠告:

  1. 升級到最新版本( 1.0.0
  2. 閱讀文檔: https//typelevel.org/cats-effect/datatypes/io.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM