对Cats Effect IO的热切评估和遗忘行为

时间:2018-05-15 16:07:13

标签: scala scala-cats

我正在将Future代码转换为IO。我的代码与此类似

def doSomething: Future[Foo] = {
  Future { 
    //some code the result of which we don't care about 
  }
  Future {
    //Foo
  }
}

然后在程序结束时,我doSomething.unsafeRunSync。如何在保留第一个Future的“即发即弃”功能的同时将这些IO转换为Future?在使用IO的异步API时,我担心以后在unsafeRunSync上调用doSomething时会意外阻止该线程。

2 个答案:

答案 0 :(得分:3)

仅使用cats-effect的解决方案可以使用IO.start。这一点,加上你永远不会加入结果Fiber的事实,将会是这样的:

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")
}

这将打印(大多数时间)类似于:

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 

最后,以下是有关FiberIO.shift

的详细信息

答案 1 :(得分:2)

我相信你需要以一种立即完成的方式包装第一个Future。我们忽略了exeptions,或者捕获它们,但是它们包含在它自己的线程中。参数cb是需要完成的承诺;所以我们通过立即提供一个值来缩短完成时间。

def firstFuture(implicit ec: ExecutionContext): IO[Unit] = {
  IO.async[Unit] { cb =>
    ec.execute(() => {
      try {
        //some code the result of which we don't care about
      } catch {
      }
    })
    cb(Right(()))
  }
}

在for-comprehension中,firstFuture将立即完成,即使它的线程将在其上有一个长时间运行的任务。

def doSomething(implicit ec: ExecutionContext): IO[Foo] = {
  for {
    _ <- firstFuture
    IO.async[Foo] { fb =>
      // Foo
    }
  }
}