Yuri Geinish
Yuri Geinish

Reputation: 17214

Why does Scala's Future.onComplete needs an ExecutionContext

Can't Promise.complete just run Future.onComplete's callback, and not go all the way through a ExecutionContext and, as I understand it, schedule Future.onComplete's callback for later and potentially run it in another thread?

Upvotes: 5

Views: 1468

Answers (2)

Kolmar
Kolmar

Reputation: 14224

You can provide your own ExecutionContext to onComplete, that will run the code on the same thread:

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

You can even make it implicit, and for cases where you want the execution to take place in another thread, you can provide scala.concurrent.ExecutionContext.global or some other context.

Here is a test, how it works:

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

Running testContext() will print

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

Upvotes: 4

Eugene Zhulenev
Eugene Zhulenev

Reputation: 9734

It's design decision for implementing scala Futures, all operations (map, flatMap, etc...) requires implicit ExecutionContext.

If you'd like to have better thread reusability and less context switches between threads I'd suggest you to take a look at scalaz Task, slightly different abstraction for delayed computations: http://timperrett.com/2014/07/20/scalaz-task-the-missing-documentation/

Upvotes: 1

Related Questions