我将在此处对(当前)接受的答案提出异议。根据我的评论,这并不是将两个期货 zip 结合在一起的真正正确 方式。正确的方法就是这样:
f1 zip f2
另一个答案:
for (x <- f1; y <- f2) yield (x, y)
虽然这会起作用,但在 f2 是一个产生未来的表达式的情况下(就像在这个问题中一样),它并不平行。如果是这种情况,f2 将在第一个 future 完成 [1] 之前构建。虽然zip 已经按照flatMap 以相同的方式实现,但因为它的参数是严格的,第二个future 已经在运行(当然取决于执行上下文)。
它也更简洁!
[1] - 这可以通过观察y(由f1 计算的值)在f2 的构造范围内来看出
附录
这很容易证明:
scala> import scala.concurrent._; import ExecutionContext.Implicits.global
import scala.concurrent._
import ExecutionContext.Implicits.global
scala> def createAndStartFuture(i: Int): Future[Int] = Future {
| println(s"starting $i in ${Thread.currentThread.getName} at ${java.time.Instant.now()}")
| Thread.sleep(20000L)
| i
| }
createAndStartFuture: (i: Int)scala.concurrent.Future[Int]
有了这个:
scala> for (x <- createAndStartFuture(1); y <- createAndStartFuture(2)) yield (x, y)
starting 1 in scala-execution-context-global-34 at 2017-05-05T10:29:47.635Z
res15: scala.concurrent.Future[(Int, Int)] = Future(<not completed>)
// Waits 20s
starting 2 in scala-execution-context-global-32 at 2017-05-05T10:30:07.636Z
但带拉链
scala> createAndStartFuture(1) zip createAndStartFuture(2)
starting 1 in scala-execution-context-global-34 at 2017-05-05T10:30:45.434Z
starting 2 in scala-execution-context-global-32 at 2017-05-05T10:30:45.434Z
res16: scala.concurrent.Future[(Int, Int)] = Future(<not completed>)