[英]Scala's “for comprehension” with futures
我正在閱讀斯卡拉食譜( http://shop.oreilly.com/product/0636920026914.do )
有一個與未來使用有關的例子涉及到理解。
到目前為止,我對理解的理解是,當與集合一起使用時,它將產生具有相同類型的另一個集合。 例如,如果每個futureX
的類型為Future[Int]
,則以下類型也應為Future[Int]
類型:
for {
r1 <- future1
r2 <- future2
r3 <- future3
} yield (r1+r2+r3)
有人可以解釋一下使用<-
在這段代碼中究竟發生了什么嗎? 我知道如果它是一個生成器,它將通過循環獲取每個元素。
首先是為了理解。 它在很多時候得到了回答,它是對幾個withFilter
操作的抽象: map
, flatMap
, withFilter
。 當你使用<-
,scalac將這些行desugar到monadic flatMap
:
r <- monad
into monad.flatMap(r => ... )
它看起來像一個命令式計算(monad是什么),你將計算結果綁定到r
。 並且yield
部分被解雇到map
呼叫中。 結果類型取決於monad
的類型。
Future
特征具有flatMap
和map
函數,因此我們可以使用它來理解它。 在您的示例中可以將以下代碼置於:
future1.flatMap(r1 => future2.flatMap(r2 => future3.map(r3 => r1 + r2 + r3) ) )
不言而喻,如果future2
執行依賴於r1
則無法逃避順序執行,但如果將來的計算是獨立的,則有兩種選擇。 您可以強制執行順序執行,也可以允許並行執行。 您無法強制執行后者,因為執行上下文將處理此問題。
val res = for {
r1 <- computationReturningFuture1(...)
r2 <- computationReturningFuture2(...)
r3 <- computationReturningFuture3(...)
} yield (r1+r2+r3)
將始終按順序運行。 它可以通過脫糖,在此之后,后續很容易解釋computationReturningFutureX
調用只有flatMaps內部調用,即
computationReturningFuture1(...).flatMap(r1 =>
computationReturningFuture2(...).flatMap(r2 =>
computationReturningFuture3(...).map(r3 => r1 + r2 + r3) ) )
但是,這可以並行運行,並且for comprehension聚合結果:
val future1 = computationReturningFuture1(...)
val future2 = computationReturningFuture2(...)
val future3 = computationReturningFuture3(...)
val res = for {
r1 <- future1
r2 <- future2
r3 <- future3
} yield (r1+r2+r3)
要細說了這些現有的答案,一個簡單的結果,以說明如何for
理解作品。
它有點冗長的功能,但值得深入研究。
一個給出一系列整數的函數
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]]
一個給我們一系列字符的函數
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]]
在 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>)
對於以下這些行,我們可以看出所有函數調用都是同步的,即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.
使這些函數createAsciiChars
, createIntegers
調用之外的for
comprehension將是異步執行。
如果可能,它允許r1
, r2
, r3
並行運行。 這可能是不可能的,這取決於有多少線程可用於執行Future計算,但是通過使用這種語法,您告訴編譯器如果可能的話並行運行這些計算,然后在完成所有計算后執行yield()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.