for-comprehension vs Future.sequence

时间:2015-09-12 21:08:53

标签: scala future for-comprehension

我的机器上有4个核心。

我认为for-comprehension安排在paraller中的东西(不依赖于之前的结果......相同的flatMap):

val stuffResult: Future[String] = for {
   stuff1 <- service1.doServiceStuff("service 1")  // worker-5 (4+1)
   stuff2 <- service1.doServiceStuff("service 2")
   stuff3 <- service1.doServiceStuff("service 3")
   stuff4 <- service1.doServiceStuff("service 4")
 } yield (stuff1 + ", " + stuff2 + ", "+ stuff3 + ", " + stuff4)

,其中

 class Service {

 implicit val blockingExContext = scala.concurrent.ExecutionContext.fromExecutor(null: Executor)

 def doServiceStuff(name:String): Future[String] = {
    Future {
      blocking {    
        println ( s"start ${name} on " + Thread.currentThread.getName)
        Thread.sleep(5000)
        "stuff_done"
      }
    }
  }
}

但我所看到的是(每一步需要约5秒):

  • 在ForkJoinPool-3-worker-5
  • 上启动服务1
  • 在ForkJoinPool-3-worker-5
  • 上启动服务2
  • 在ForkJoinPool-3-worker-5
  • 上启动服务3
  • 错误:java.util.concurrent.TimeoutException:期货在[10秒]之后超时

所有在一个线程上运行,而不是使用现有的FREE线程并尽可能快地完成 - 在~5秒内。

但如果我选择:

val stuff1 = service1.doServiceStuff("service 1")
val stuff2 = service1.doServiceStuff("service 2")
val stuff3 = service1.doServiceStuff("service 3")
val stuff4 = service1.doServiceStuff("service 4")

Future.sequence(List(stuff1, stuff2, stuff3, stuff4)).map { list =>
  list.foldLeft("") { (acc, x) => acc + " " + x }
}
..

所有结束都在5秒内完成。

pont for-comprehension顺序工作?是吗?

1 个答案:

答案 0 :(得分:3)

它无法按顺序工作,它只是无法启动Future直到它们被创建(在您的flatMap之前的Future中会发生这种情况,所以你如果你想并行处理它们(使用通常的隐式ExecutionContext),需要提前创建它们。

可能this tutorial解释得更好(它使withFilter复杂化):

  

购买期限仅在usdQuote和chfQuote时完成   完成 - 这取决于这两个期货的价值所以它   自己的计算不能早点开始。

     

上面的理解被翻译成:

     

val purchase = usdQuote flatMap { usd => chfQuote   .withFilter(chf => isProfitable(usd, chf))   .map(chf => connection.buy(amount, chf)) }

     

比理解力更难掌握,但我们更好地分析它   了解flatMap操作。 flatMap操作映射自己的   重视其他未来。一旦这个不同的未来完成,   由此产生的未来完成了它的价值。在我们的例子中,   flatMap使用usdQuote future的值来映射值   chfQuote指向第三个未来发送购买某个特定的请求   瑞士法郎金额。由此产生的未来购买完成   只有从地图返回的第三个未来完成。

您真正需要的是map2而不是flatMap,因为您不使用上一个Future的返回值来创建新的Future