为什么 Scala 的 Future.onComplete 需要一个 ExecutionContext

Why does Scala's Future.onComplete needs an ExecutionContext

不能 Promise.complete 只是 运行 Future.onComplete 的回调,而不是一直通过 ExecutionContext 并且,据我所知,安排 Future.onComplete 稍后的回调,可能 运行 它在另一个线程中?

这是实现 scala Futures 的设计决策,所有操作(map、flatMap 等...)都需要隐式 ExecutionContext。

如果您想要更好的线程可重用性和线程之间更少的上下文切换,我建议您看一下 scalaz Task,延迟计算的抽象略有不同:http://timperrett.com/2014/07/20/scalaz-task-the-missing-documentation/

您可以将自己的 ExecutionContext 提供给 onComplete,这将 运行 同一线程上的代码:

val immediateContext: ExecutionContext = new ExecutionContext {
  def execute(runnable: Runnable) {
    runnable.run()
  }
  def reportFailure(cause: Throwable) {}
}

您甚至可以将其设置为 implicit,并且对于您希望在另一个线程中执行的情况,您可以提供 scala.concurrent.ExecutionContext.global 或其他一些上下文。

这是一个测试,它是如何工作的:

val immediateContext: ExecutionContext = new ExecutionContext {
  override def reportFailure(cause: Throwable): Unit = {}
  override def execute(runnable: Runnable): Unit = {
    println("Executing")
    runnable.run()
    println("Executed")
  }
}

def testContext(): Unit = {
  println("Scheduling on an uncompleted future")
  val p = Promise[Int]()
  println("Scheduling")
  p.future.onComplete { _ => println("Completed") }(immediateContext)
  println("Scheduled")
  p.complete(Success(5))

  println()

  println("Scheduling on an already completed future")
  val p2 = Promise[Int]().complete(Success(5))
  println("Scheduling")
  p2.future.map { n =>
    println("Mapping")
    n * 2
  }(immediateContext).onComplete{
    case Success(n) => println(s"Completed: $n") 
    case _ =>
  }(immediateContext)
  println("Scheduled")

  println()

  println("Using scala.concurrent.ExecutionContext.global for comparison")
  val p3 = Promise[Int]().complete(Success(5))
  println("Scheduling")
  p3.future.onComplete {
    _ => println("Completed")
  }(concurrent.ExecutionContext.global)
  println("Scheduled")
}

运行 testContext() 将打印

Scheduling on an uncompleted future
Scheduling
Scheduled
Executing
Completed
Executed

Scheduling on an already completed future
Scheduling
Executing
Mapping
Executed
Executing
Completed: 10
Executed
Scheduled

Using scala.concurrent.ExecutionContext.global for comparison
Scheduling
Scheduled
Completed