使用Scala期货时,将具有相同执行上下文的链接回调优化为同步调用吗?

时间:2013-11-05 17:08:52

标签: scala future scala-2.10

Scala 2.10中的新Future为每个异步调用操作的操作使用执行上下文(包括mapfilter等)。这是否意味着每个操作将始终通过执行上下文单独调用,或者在使用相同的执行上下文链接多个转换/过滤器​​时是否可以优化此步骤?

即。如果执行f.map(...).filter(...).map(...),所有具有相同的执行上下文,这将调用execute()一次(因为它足够巧妙地从上面组成同步函数),或三次?

如果scala的未来没有进行上述优化,是否有一个替代框架更适合做上述的长链组合?

1 个答案:

答案 0 :(得分:10)

我无法提供任何文档链接,这些链接将清楚地说明将要发生的事情,但我们可以进行一个简单的实验来回答您的问题。

只需打开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) 

它将打印:

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

因此,对于您正在执行的每个操作都会调用execute(并且您可以在文档中检查每个函数,如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

  

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

     

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

     

重要说明:Future不包含任何错误处理,通常只能用作想要构建Future功能但希望设计自己错误的库编写者的构建块处理策略。有关通过正确错误处理扩展scalaz.concurrent.Task的类型,请参阅Future - 它只是Future[Either[Throwable,A]]的包装器,具有许多其他便利功能。