I'm converting Future
code to IO
. I have code similar to this
def doSomething: Future[Foo] = {
Future {
//some code the result of which we don't care about
}
Future {
//Foo
}
}
And then at the end of the program, I doSomething.unsafeRunSync
. How do I convert these Future
s to IO
s while maintaining the fire-and-forget functionality of the first Future
? In using IO
's async API, I am worried about accidentally blocking the thread when I later call unsafeRunSync
on doSomething
.
Companion object IO An IO is a data structure that represents just a description of a side effectful computation. IO can describe synchronous or asynchronous computations that: on evaluation yield exactly one result 2.
Cats is a library which provides abstractions for functional programming in the Scala programming language. Scala supports both object-oriented and functional programming, and this is reflected in the hybrid approach of the standard library.
You can think of fibers as being lightweight threads, a fiber being a concurrency primitive for doing cooperative multi-tasking. trait Fiber[F[_], A] { def cancel: F[Unit] def join: F[A] } For example a Fiber value is the result of evaluating IO.start : import cats.effect.{Fiber, IO} import scala.concurrent.
A solution that uses only cats-effect
could use IO.start
. This, combined with the fact that you will then never join the resulting Fiber
, will look something like this:
import cats.effect._
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
object ExampleApp extends App{
val fireAndForget =
IO(println("Side effect pre-sleep")) *>
IO.sleep(2.seconds) *>
IO(println("Side effect post-sleep"))
val toBeUsed = IO{
println("Inside second one")
42
}
val result = for {
fiber <- IO.shift *> fireAndForget.start
res <- toBeUsed.handleErrorWith { error =>
// This is just in case you 'toBeUsed' can actually fail,
// and you might want to cancel the original side-effecting IO
fiber.cancel *> IO.raiseError(error) }
} yield res
println(result.unsafeRunSync())
println("Waiting 3 seconds...")
IO.sleep(3.seconds).unsafeRunSync()
println("Done")
}
This will print (most of the times) something similar to:
Side effect pre-sleep
Inside second one
42 // Up until here, will be printed right away
Waiting 3 seconds... // It will then be waiting a while
Side effect post-sleep // ...at which point the side effecting code terminates
Done
Finally, here are more details about Fiber and IO.shift
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With