2015-01-20 2 views
3

Не может Promise.complete просто запустить Future.onComplete «s обратный вызова, а не пройти весь путь через ExecutionContext и, как я понимаю, график Future.onComplete» s обратного вызова для последующего использования и потенциально запустить его в другом потоке?Почему Future.onComplete Scala нуждается в ExecutionContext

ответ

3

Вы можете предоставить свой собственный 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 
1

Это дизайнерское решение для реализации фреймов scala, все операции (map, flatMap и т. Д.) Требуют неявного ExecutionContext.

Если вы хотите, чтобы лучше нить повторного использования и меньше переключения контекста между потоками я предлагаю вам взглянуть на scalaz Task, немного отличается абстракции для отсроченных вычислений: http://timperrett.com/2014/07/20/scalaz-task-the-missing-documentation/

Смежные вопросы