Scala 对期货的“理解”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19045936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala's "for comprehension" with futures
提问by nish1013
I am reading through the Scala Cookbook (http://shop.oreilly.com/product/0636920026914.do)
我正在阅读 Scala Cookbook ( http://shop.oreilly.com/product/0636920026914.do)
There is an example related to Future use that involves for comprehension.
有一个与 Future use 相关的示例,涉及理解。
So far my understanding about for comprehension is when use with a collection it will produce another collection with the same type. For example, if each futureXis of type Future[Int], the following should also be of type Future[Int]:
到目前为止,我对理解的理解是,当与一个集合一起使用时,它将产生另一个具有相同类型的集合。例如,如果每个 futureX都是 type Future[Int],则以下也应该是 type Future[Int]:
for {
r1 <- future1
r2 <- future2
r3 <- future3
} yield (r1+r2+r3)
Could someone explain me what exactly happening when use <-in this code?
I know if it was a generator it will fetch each element by looping.
有人能解释一下<-在这段代码中使用时到底发生了什么吗?我知道如果它是一个生成器,它将通过循环获取每个元素。
回答by 4lex1v
First about for comprehension. It was answered on SO many many times, that it's an abstraction over a couple of monadic operations: map, flatMap, withFilter. When you use <-, scalac desugars this lines into monadic flatMap:
首先关于理解。它被多次回答,它是对几个 monadic 操作的抽象:map, flatMap, withFilter。当您使用<-scalac 时,scalac 将此行脱糖为 monadic flatMap:
r <- monadinto monad.flatMap(r => ... )
r <- monad进入 monad.flatMap(r => ... )
it looks like an imperative computation (what a monad is all about), you bind a computation result to the r. And yieldpart is desugared into mapcall. Result type depends on the type of monad's.
它看起来像一个命令式计算(monad 的全部内容),您将计算结果绑定到r. 而yield部分被脱到map呼叫。结果类型取决于 的类型monad。
Futuretrait has a flatMapand mapfunctions, so we can use for comprehension with it. In your example can be desugared into the following code:
Futuretrait 有一个flatMap和map函数,所以我们可以用它来理解它。在您的示例中可以将糖化为以下代码:
future1.flatMap(r1 => future2.flatMap(r2 => future3.map(r3 => r1 + r2 + r3) ) )
Parallelism aside
并行性不谈
It goes without saying that if execution of future2depends on r1then you can't escape sequential execution, but if the future computations are independent, you have two choices. You can enforce sequential execution, or allowfor parallel execution. You can't enforcethe latter, as the execution context will handle this.
不言而喻,如果执行future2依赖于r1那么你就不能逃避顺序执行,但是如果未来的计算是独立的,你有两个选择。您可以强制执行顺序执行,或允许并行执行。您不能强制执行后者,因为执行上下文将处理此问题。
val res = for {
r1 <- computationReturningFuture1(...)
r2 <- computationReturningFuture2(...)
r3 <- computationReturningFuture3(...)
} yield (r1+r2+r3)
will always run sequentially. It can be easily explained by the desugaring, after which the subsequent computationReturningFutureXcalls are only invoked inside of the flatMaps, i.e.
将始终按顺序运行。可以很容易地通过 desugaring 来解释,之后后续的computationReturningFutureX调用只会在 flatMaps 内部调用,即
computationReturningFuture1(...).flatMap(r1 =>
computationReturningFuture2(...).flatMap(r2 =>
computationReturningFuture3(...).map(r3 => r1 + r2 + r3) ) )
However this is able to run in parallel and the for comprehension aggregates the results:
然而,这能够并行运行,并且 for comprehension 聚合结果:
val future1 = computationReturningFuture1(...)
val future2 = computationReturningFuture2(...)
val future3 = computationReturningFuture3(...)
val res = for {
r1 <- future1
r2 <- future2
r3 <- future3
} yield (r1+r2+r3)
回答by Puneeth Reddy V
To elaborate those existing answers here a simple result to demonstrate how forcomprehension works.
为了详细说明这些现有的答案,这里有一个简单的结果来演示for理解是如何工作的。
Its bit lengthy functions yet they worth taking look into it.
它的功能有点长,但值得研究一下。
A function that give us a range of integers
一个给我们一个整数范围的函数
scala> def createIntegers = Future{
println("INT "+ Thread.currentThread().getName+" Begin.")
val returnValue = List.range(1, 256)
println("INT "+ Thread.currentThread().getName+" End.")
returnValue
}
createIntegers: createIntegers: scala.concurrent.Future[List[Int]]
A function that give us a range of chars
一个为我们提供一系列字符的函数
scala> def createAsciiChars = Future{
println("CHAR "+ Thread.currentThread().getName+" Begin.")
val returnValue = new ListBuffer[Char]
for (i <- 1 to 256){
returnValue += i.toChar
}
println("CHAR "+ Thread.currentThread().getName+" End.")
returnValue
}
createAsciiChars: scala.concurrent.Future[scala.collection.mutable.ListBuffer[Char]]
Using these function calls withinthe for comprehension.
在for comprehension 中使用这些函数调用。
scala> val result = for{
i <- createIntegers
s <- createAsciiChars
} yield i.zip(s)
Await.result(result, Duration.Inf)
result: scala.concurrent.Future[List[(Int, Char)]] = Future(<not completed>)
For these below lines we can make out that all the function calls are synchronous i.e. createAsciiCharsfunction call is not executeduntil createIntegerscompletes its execution.
对于下面这些行,我们可以确定所有函数调用都是同步的,即createAsciiChars函数调用在完成执行之前不会createIntegers执行。
scala> INT scala-execution-context-global-27 Begin.
INT scala-execution-context-global-27 End.
CHAR scala-execution-context-global-28 Begin.
CHAR scala-execution-context-global-28 End.
Making these function createAsciiChars, createIntegerscalls outside the forcomprehensions will be asynchronous execution.
使这些函数createAsciiChars,理解createIntegers之外的调用for将是异步执行的。
回答by Jonathan Stray
It allows r1, r2, r3to run in parallel, if possible. It may not be possible, depending things like how many threads are available to execute Future computations, but by using this syntax you are telling the compiler to run these computations in parallel if possible, then execute the yield()when all have completed.
如果可能,它允许r1,并行运行。这可能是不可能的,这取决于有多少线程可用于执行 Future 计算,但是通过使用此语法,您可以告诉编译器在可能的情况下并行运行这些计算,然后在全部完成后执行。r2r3yield()

