Reputation: 27375
I'm trying to understand asynchronous computation by cats.effect.IO
examples and got some misunderstanding. The unsafe
method unsafeRunAsync
seems like running the underlying effect asynchronously (I expected that some ContextShift
to be provided). But the method looks simply like this:
final def unsafeRunAsync(cb: Either[Throwable, A] => Unit): Unit =
IORunLoop.start(this, cb)
Neither ContextShift
nor ExecutionContext
is provided. Here is the very simple example:
object TestIo extends App {
println(s"Main thread = ${Thread.currentThread().getName}")
val io = IO {
println(s"Effect thread = ${Thread.currentThread().getName}")
Thread.sleep(1000)
}
io.unsafeRunAsync(_ => println(s"Callback thread = ${Thread.currentThread().getName}"))
println(s"Finished")
}
The output is
Main thread = main
Effect thread = main
Callback thread = main
Finished
As you can see everything here is run in the main thread synchronously. Can you please explain unsafeRunAsync
? To me it seems the same as unsafeRunSync
.
Upvotes: 7
Views: 694
Reputation: 14803
About
Neither ContextShift nor ExecutionContext is provided.
There is a context switch in cats.effect.IO
See this blog: https://www.jaspervanzandbeek.com/scala/cats-io-monad/
Here an example from there:
def blockingOperation(): String = {
// Read from file
...
}
val result: IO[String] = for {
_ <- IO.shift(executionContextForBlockingOperations)
result <- IO { blockingOperation() }
_ <- IO.shift(mainExecutionContext)
} yield result
Upvotes: 4
Reputation: 16935
The difference between unsafeRunSync
and unsafeRunAsync
is whether or not the thread is blocked. You're forcing your thread to block by using Thread.sleep
in the body of your IO
monad. By doing this, you're forcing it to behave synchronously.
Because IO
is a monad, it will still do its computation sequentially, though. Therefore, your prints will always be in that order.
Upvotes: 2