深入理解 Scala Futures

Scala Futures in For Comprehension

我正在努力研究 Scala,我想知道以下内容的作用:

val fFuture: Future[Int] = Future { println("f called"); 3 }                                                                                                                    
val gFuture: Future[Int] = Future { println("g called"); 4 }                                                                                                                    

for {
    f <- fFuture
    g <- gFuture
} yield f  

期货是在 for comprehension 内部执行的,对吗?那么 f 在 yield 语句中做了什么?这是否意味着它可用?如果这是在函数内部,那会被认为是 return value 吗?

在你的场景中,你不必使用 for comprehension,你可以简单地使用 OnComplete。

ffuture.OnComplete {
Case Success(result) => println(s"$result')
Case Failure(ex) => ex.printStackTrace
}

当你的未来依赖于其他未来时,就需要理解 喜欢:

var result =  for {
        f <- fFuture
        g <- f
    } yield g

这里g future 会在f 完成后解决, 并且 yield 将 return 无论你的结果是什么 returning。在这种情况下,它将是 Future[Int]。 使用 yield 你可以做类似的事情。

yield g+f

要读取结果,您只需使用

result.onSuccess or onComplete

对于 Futures,我发现这篇文章是最好的一篇: http://alvinalexander.com/scala/concurrency-with-scala-futures-tutorials-examples

我会说是的,这类似于函数中的 return 值。 但这是为了理解语法,你不能使用 return 语句。 For comprehension is a better way to write map.

期货在这里开始执行:

val fFuture: Future[Int] = Future { println("f called"); 3 }                                                                                                                    
val gFuture: Future[Int] = Future { println("g called"); 4 } 

所以两个执行是并行开始的。但是,如果您不小心将 Future{...} 放入 for-comprehension - 它们将按顺序执行。

For-comprehension 基本上订阅两个结果并将其合并为一个 Future。但是,在您的情况下,似乎忽略了第二个未来的结果,这是没有意义的。有意义的代码:

for {
    f <- fFuture
    g <- gFuture
} yield f + g

此代码 returns Future[Int](与示例中的代码相同)。如果你从这个 Future 中提取价值——你会得到 3 + 4 = 7。然而,它仍然不是最佳方法,因为您的计算是独立的,并且开发人员错误(如上所述)导致它们顺序执行的可能性仍然很高,因此独立计算的推荐方法是:

(fFuture zip gFuture) map {
  case (f, g) => f + g
}

这段代码是引用透明的,意思是即使你用 Future{...} 替换 fFuture - 它仍然表现相同(在 Future 的情况下 - 它们将被执行并发,但对于其他并发原语可能有所不同)

for-comprehension 哪里有意义?这里:

for {
    f <- Future{... 9}
    g <- if (f > 0) Future{...} else Future{...}
} yield g

因为 g 依赖于 f 这里 - 没有办法 运行 并行,所以 for 提供了一种非阻塞的方式来组合几个 Futures

Scala Futures 是急切求值的,这意味着它们的值会立即在单独的线程中计算。

当您 运行 依赖于未来结果的操作时,当前线程将阻塞等待直到它被评估。如果您使用 map 或 flatMap 等组合器方法转换 Future,您将获得另一个代表最终结果的 Future(代码 运行 执行这些操作不需要阻塞)。

因此在您的示例中,for 理解被编译器脱糖为以下表达式:

fFuture.flatMap(f => gFuture.map(g => f + g))

它本身是在另一个线程中计算的 Future[Int]。