我试图绕过Scala,我想知道以下是什么:
a: a.o
$(COMPILER) a.o -o a
期货是在理解中执行的,对吗?那么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
在yield语句中做了什么?这只是意味着它可用吗?如果它在函数内部,那被认为是f
吗?
答案 0 :(得分:4)
期货开始在这里执行:
val fFuture: Future[Int] = Future { println("f called"); 3 }
val gFuture: Future[Int] = Future { println("g called"); 4 }
因此两个执行都是并行开始的。但是,如果你不小心将Future{...}
置于理解之中 - 它们将按顺序执行。
for-comprehension基本上订阅并将两个结果合并为一个Future。但是,在你的情况下,似乎第二个未来的结果被忽略了,这是没有意义的。有意义的代码:
for {
f <- fFuture
g <- gFuture
} yield f + g
此代码返回Future[Int]
(与示例中的代码相同)。如果你从这个未来中提取价值 - 你得到3 + 4 = 7
。然而,它仍然不是最佳方法,因为您的计算是独立的,并且开发人员错误的概率(如上所述)使得它们顺序仍然很高,因此建议的独立计算方法是:
(fFuture zip gFuture) map {
case (f, g) => f + g
}
此代码的引用是透明的,即使您将fFuture
替换为Future{...}
- 它仍然表现相同(如果Future
- 它们将以并行方式执行,但它可能与其他并发原语不同)
for-comprehension
在哪里才有意义?这里:
for {
f <- Future{... 9}
g <- if (f > 0) Future{...} else Future{...}
} yield g
由于g
取决于此处的f
- 无法并行运行,因此for
提供了一种无阻塞的方式来组合多个Future
s < / p>
答案 1 :(得分:1)
Scala期货受到热切评估,这意味着它们的价值会立即在一个单独的线程中计算。
当你运行依赖于未来结果的操作时,当前线程将阻塞等待直到它被评估。如果使用组合方法(如map或flatMap)转换Futures,则会获得另一个表示最终结果的Future(运行这些操作的代码不需要阻止)。
因此,在您的示例中,编译器将for comprehension视为以下表达式:
fFuture.flatMap(f => gFuture.map(g => f + g))
本身是另一个线程中计算的Future [Int]。
答案 2 :(得分:-2)
在你的场景中,你不必使用理解,你可以简单地使用OnComplete。
ffuture.OnComplete {
Case Success(result) => println(s"$result')
Case Failure(ex) => ex.printStackTrace
}
当你的未来依赖于其他未来时需要理解 像:
var result = for {
f <- fFuture
g <- f
} yield g
此后g将在f完成后解决, 并且产量将返回您返回的结果。在这种情况下,它将是Future [Int]。 有了收益率,你可以做类似的事情。
yield g+f
要阅读结果,您只需使用
即可result.onSuccess or onComplete
对于期货,我发现这篇文章是最好的: http://alvinalexander.com/scala/concurrency-with-scala-futures-tutorials-examples
我会说是,这类似于函数中的返回值。 但这是为了理解语法,你不能使用return语句。 理解是一种更好的编写地图的方法。