Mic*_*tte 8 monads functional-programming scala io-monad scala-cats
以下是使用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()
}
Run Code Online (Sandbox Code Playgroud)
要运行它,您需要添加:
libraryDependencies ++= Seq(
"org.typelevel" %% "cats" % "0.9.0",
"org.typelevel" %% "cats-effect" % "0.3"
),
Run Code Online (Sandbox Code Playgroud)
到你的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
*/
Run Code Online (Sandbox Code Playgroud)
基本上,我不明白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,您还可以evalOn在指定的线程池中ContextShift执行IO操作,然后切换回"全局",我想这就是您想要的.
另外,在这个例子中,forkAsync和forkSync有什么区别?
您forkSync触发执行Runnable,但不等待其完成.这是一场火灾,忘记了.这意味着后续的链式操作不会进行反压.
一些忠告:
1.0.0)