15

mapScala 2.10 中的新 Future 对每个异步调用操作的操作(包括、filter等)使用执行上下文。这是否意味着每个动作都将始终通过执行上下文单独调用,或者当链接多个转换/过滤器​​时,这一步是否有可能被优化掉,每个都使用相同的执行上下文?

即如果做f.map(...).filter(...).map(...),都具有相同的执行上下文,这个调用execute()是一次(因为它足够聪明,可以从上面组合一个同步函数),还是三次?

如果 scala 未来不进行上述优化,是否有更适合长链组合的替代框架来完成上述优化?

4

1 回答 1

11

我无法提供任何可以清楚说明实际情况的文档链接,但我们可以进行一个简单的实验来回答您的问题。

只需打开 Scala REPL 并粘贴以下代码:

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) 

它将打印:

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

因此,您正在执行的每个操作都会调用执行(并且您可以在文档中查看每个函数(如 map 或 filter)将 ExecutionContext 作为隐式参数:http ://www.scala-lang.org/api/2.10.6 /#scala.concurrent.Future )

如果您正在寻找替代框架,您应该检查 scalaz Futures。我对他们没有经验,但他们似乎是你正在寻找的。检查此线程:https ://groups.google.com/forum/#!msg/scalaz/-PuakIf-g_4/7ydrU5VIfDQJ

Futurescala 2.10 中的实现不同mapflatMap它不会产生新任务,也不需要隐式ExecutionContext. 相反,map只是flatMap添加到将由“当前”线程运行的当前(蹦床)延续,除非通过Future.forkor明确分叉Future.apply。这意味着Future实现了比 2.10 实现更好的线程重用,并避免了不必要的线程池提交周期。

Future也不同于 scala 2.10Future类型,因为它不一定代表正在运行的计算。相反,我们使用接口的函数明确地scalaz.Nondeterminsm重新引入了不确定性。这简化了我们的实现并使代码更易于推理,因为效果的顺序和不确定性点是完全明确的,并且不依赖于 Scala 的评估顺序。

重要说明:不包括任何错误处理,并且通常只能由希望构建's 功能但希望设计自己的错误处理策略Future的库编写者用作构建块。Future参见scalaz.concurrent.Task一个扩展Future了适当的错误处理的类型——它只是一个Future[Either[Throwable,A]]带有许多附加便利功能的包装器。

于 2013-12-28T00:28:42.137 回答