返回Future [(Int,Int)]而不是(Future [Int],Future [Int])

时间:2017-05-05 03:03:40

标签: scala

我有以下未来:

Right-click the sheet's Tab, click "Unprotect Sheet..."
Enter your password and click OK

我需要以下代码才能返回def f1 = Future {1} def f2 = Future {2}

Future[(Int,Int)]

而不是val future = // function that returns a future future.flatMap { val x1 = f1 val x2 = f2 (x1,x2) // This returns Future[Int],Future[Int] } 我需要函数返回(Future[Int],Future[Int])。如何转换呢?

2 个答案:

答案 0 :(得分:2)

这是一个理解的经典用例。

for {
    x1 <- f1
    x2 <- f2
} yield (x1, x2)

这相当于flatmap后跟地图

f1.flatMap(x1 => f2.map(x2 => (x1,x2)))

由于在x1准备好之前你不会到达f1.flatMap的内部,所以这段代码将按顺序执行。

如果您希望期货同时执行,您可以在理解之前实例化期货。

val future1 = f1
val future2 = f2
for {
    x1 <- future1
    x2 <- future2
} yield (x1, x2)

答案 1 :(得分:2)

我将在这里接受(目前)接受的答案。根据我的评论,这并不是正确的方式将压缩两种方式放在一起。正确的方法就是:

f1 zip f2

另一个答案:

for (x <- f1; y <- f2) yield (x, y)

虽然这会起作用,但在f2是一个产生未来的表达式(就像在这个问题中一样)的情况下,它并不平行。如果是这种情况,则在第一个未来完成 [1] 之前,不会构建f2。虽然zipflatMap的方式以同样的方式实现,但因为它的参数是严格的,所以第二个未来已经在运行(当然,这取决于执行上下文)。

它也更简洁!

[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>)