簡體   English   中英

斯卡拉對期貨的“理解”

[英]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操作的抽象: mapflatMapwithFilter 當你使用<- ,scalac將這些行desugar到monadic flatMap

r <- monad into monad.flatMap(r => ... )

它看起來像一個命令式計算(monad是什么),你將計算結果綁定到r 並且yield部分被解雇到map呼叫中。 結果類型取決於monad的類型。

Future特征具有flatMapmap函數,因此我們可以使用它來理解它。 在您的示例中可以將以下代碼置於:

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.

使這些函數createAsciiCharscreateIntegers調用之外的for comprehension將是異步執行。

如果可能,它允許r1r2r3並行運行。 這可能是不可能的,這取決於有多少線程可用於執行Future計算,但是通過使用這種語法,您告訴編譯器如果可能的話並行運行這些計算,然后在完成所有計算后執行yield()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM