When using Scala futures, will chained callbacks with the same execution context be optimised into synchronous calls?

﹥>﹥吖頭↗ 提交于 2019-12-03 10:29:57
Piotr Kukielka

I cannot provide any link to documentation which will clearly state what will really happen, but we can conduct a simple experiment which will answer your question.

Just open the Scala REPL and paste the following code:

import java.util.concurrent.Executors
import scala.concurrent._

implicit val ec = new ExecutionContext {
    val threadPool = Executors.newFixedThreadPool(1000);

    def execute(runnable: Runnable) {
        threadPool.submit(runnable)
        println("execute!")
    }

    def reportFailure(t: Throwable) {}
}

future { 1 } map(_ + 1) filter (_ > 0) map (_ + 2) 

It will print:

scala> future { 1 } map(_ + 1) filter (_ > 0) map (_ + 2)
execute!
execute!
execute!
execute!
res0: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@7ef3de76

So execute is called for every single operation you are doing (and as you can check in the documentation each function like map or filter takes ExecutionContext as an implicit parameter: http://www.scala-lang.org/api/2.10.6/#scala.concurrent.Future)

If you are looking for an alternative framework you should check scalaz Futures. I have no experience with them, but they seems to be what you are looking for. Check this thread: https://groups.google.com/forum/#!msg/scalaz/-PuakIf-g_4/7ydrU5VIfDQJ

Unlike the Future implementation in scala 2.10, map and flatMap do NOT spawn new tasks and do not require an implicit ExecutionContext. Instead, map and flatMap merely add to the current (trampolined) continuation that will be run by the 'current' thread, unless explicitly forked via Future.fork or Future.apply. This means that Future achieves much better thread reuse than the 2.10 implementation and avoids needless thread pool submit cycles.

Future also differs from the scala 2.10 Future type in that it does not necessarily represent a running computation. Instead, we reintroduce nondeterminism explicitly using the functions of the scalaz.Nondeterminsm interface. This simplifies our implementation and makes code easier to reason about, since the order of effects and the points of nondeterminism are made fully explicit and do not depend on Scala's evaluation order.

IMPORTANT NOTE: Future does not include any error handling and should generally only be used as a building block by library writers who want to build on Future's capabilities but wish to design their own error handling strategy. See scalaz.concurrent.Task for a type that extends Future with proper error handling -- it is merely a wrapper for Future[Either[Throwable,A]] with a number of additional convenience functions.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!