繁体   English   中英

为什么 Scala Future 在映射到迭代器时按顺序运行

[英]Why is Scala Future running sequentially when mapped over an Iterator

所以我很困惑为什么用 Futures 映射一个迭代器会使它按顺序运行。 考虑以下代码 -

import org.scalameter._

object IteratorVsListInFutures extends App {
  def slowFunction = Thread.sleep(1000)

  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent._
  import duration._

  println("Should take approximately 4000 ms or 4 sec")
  println{
    withWarmer(new Warmer.Default) measure {
      List(1,2,3,4).foreach(_ => slowFunction)
    }
  }

  println("Should take approximately 1 second")
  println {
    withWarmer(new Warmer.Default) measure {
      val futures: Seq[Future[Unit]] = List(1,2,3,4).map(_ => Future { slowFunction})
      futures.foreach(x => Await.result(x, 10.seconds))
    }
  }

  println("And how long does this take")
  println {
    withWarmer(new Warmer.Default) measure {
      val futures = List(1,2,3,4).iterator.map(_ => Future { slowFunction})
      futures.foreach(x => Await.result(x, 10.seconds))
    }
  }

}

我得到以下结果 -

Should take approximately 4000 ms or 4 sec
4012.132085 ms
Should take approximately 1 second
1004.997573 ms
And how long does this take
4016.533206 ms

Process finished with exit code 0

第一个基准与预测约 4 秒,第二个基准也与预测约 1 秒(因为期货是并行执行的)让我困惑的是为什么第三个基准也是约 4 秒?

由于迭代器的非严格性质,以下

List(1,2,3,4).iterator.map(_ => Future { slowFunction })

计算为Iterator[Future[Unit]] ,这只是对要发生的转换的描述,但尚未发生。 关键是要明白

惰性集合对于描述连续的转换操作而不评估中间转换特别有用

让我们稍微重写您的示例以强调中间转换

List(1,2,3,4)
  .iterator
  .map(_ => Future { slowFunction })         // <-- intermediate transformation
  .foreach(x => Await.result(x, 10.seconds))

因此map(_ => Future { slowFunction })是没有被评估的中间转换,但这是应该启动期货的转换。 相反, map转换与foreach转换相结合,作为一个单一的转换来执行,像这样

 List(1,2,3,4)
   .foreach(_ => Await.result(Future { slowFunction }, 10.seconds) )

现在可以明确的是,我们正在等待完成Future我们移动到下一个元素,因此之前Future氏完全连续。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM