我必须与userRepository.save(User(1, "test"))
合作才能理解IO。
我认为它正在阻止线程操作,并尝试ContextShift.evalOn
正确编写代码(https://typelevel.org/cats-effect/concurrency/basics.html#blocking-threads)
implicit val contextShift: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
val blockingEC = ExecutionContext.fromExecutor(Executors.newCachedThreadPool())
def doSth(str: String): IO[Unit] = IO(println(str))
def blockingOp(str: String): IO[Unit] = IO(userRepository.save(User(1, str)))
def greeting(msg: String): IO[Unit] =
for {
_ <- doSth("Before blocking operation.")
_ <- contextShift.evalOn(blockingEC)(blockingOp("testName"))
_ <- doSth("After blocking operation")
} yield ()
val run = greeting("test").unsafeRunAsyncAndForget()
在此示例中使用了ExecutionContext.global,如何避免呢? 以及如何使用(https://monix.io/docs/3x/best-practices/blocking.html)中的monix。 我尝试了下一个,但是未执行保存操作。
private val io = Scheduler.io(name = "engine-io")
def executeBlockingIO[T](cb: => T): Future[T] = {
val p = Promise[T]()
io.execute(new Runnable {
def run() =
try {
p.success(cb)
} catch {
case NonFatal(ex) =>
logger.error(s"Uncaught I/O exception", ex)
p.failure(ex)
}
})
p.future
}
def doSth(str: String): IO[Unit] = IO(println(str))
def blockingOp(str: String): IO[Unit] = IO(userRepository.save(User(1, str)))
def greeting(msg: String): IO[Unit] =
for {
_ <- doSth("Before blocking operation.")
_ <- IO.fromFuture(IO(executeBlockingIO(blockingOp("testName"))))
_ <- doSth("After blocking operation")
} yield ()
val test = greeting("test").unsafeRunAsyncAndForget()