2017-10-10 48 views
0

我使用Redis和Scala。 Redis的任務是future,所以我必須研究未來(線程)。在斯卡拉有什麼不同,等待,Thread.sleep和理解?

我發現很多方法來等待future停止。我不知道有什麼不同。 AwaitThread.sleepfor的理解有什麼區別?

val redisResult1 = redis.set(objectId, value) 
    Await.ready(redisResult1, Duration.Inf) 

    val redisResult2 = redis.set(objectId, value) 
    for { 
    _ <- redisResult2 
    } yield { 
    "end" 
    } 

    val redisResult3 = redis.set(objectId, value) 
    while(redisResult3.isCompleted) Thread.sleep(10) 
+0

理想情況下,你應該避免等待(儘可能地推出)和連鎖期貨(如在'for'理解中那樣)。 – Thilo

+0

如果你想在while循環中輪詢,它應該是'while(!isCompleted)'。但最好使用'Await.ready',這是爲了這個確切的目的而製作的。 – Thilo

+0

hwan下面有兩個貌似好的答案,他們有什麼好處? – halfer

回答

1

好吧,讓我們從秒示例開始。 考慮下面的代碼片段:

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

object Test2{ 
    def main(args:Array[String]):Unit={ 
    val f = Future{Thread.sleep(5000); "i'm done"} 
    val r = for{ 
     _ <- f 
    } yield "completed" 
    println(r) 
    } 
} 

猜猜它會打印?它打印

Future(<not completed>) 

Process finished with exit code 0 

所以其實這裏你是不是等待將來完成時,您只需映射第一未來的結果,並返回它作爲其他未來的第一個完成後,將完成。正如你所看到的,該計劃不會等到最終的未來完成並正好退出。 for對期貨的理解是用於映射和平滑映射它們的糖語法。

Await.resultAwait.ready真的等待未來完成(或超時通過)。但是它們是以阻塞的方式實現的,所以你使用這些方法的線程將被阻塞。這並不總是很糟糕,有時可能會有所幫助。例如。在小測試程序或REPL會話中,您最終將未來計算的結果輸出到控制檯,或者例如在無論如何需要等待結果並且在等待測試時無需執行測試的情況下。

另一種看到你導致這樣的小程序的方法是使用scala.io.StdIn.readLine(),這樣主線程就會掛起而不會退出。考慮其中說明了這以下,也爲您提供了一個更多附加的方式來等待將來完成:

object Test2{ 
    def main(args:Array[String]):Unit={ 
    val f = Future{Thread.sleep(5000); "i'm done"} 
    f foreach (println(_)) 

    scala.io.StdIn.readLine() 
    } 

} 

運行它,你會看到該程序不會退出,打印的未來和退出的結果,那麼只有在您按下ENTER鍵後。

foreach應用於未來是添加onComplete偵聽器的快捷方式。非常方便的一個。

至於如果未來完成while循環不斷地檢查 - 我認爲這可能是等待,因爲它會繼續在主線程忙,浪費更多的空閒CPU電源不是依靠高效地實現Await.result最糟糕的方式。阻礙其他事情也可能是高效率和低效率的。

爲了理解所有這些有未來的東西,你需要清楚地認識到,未來的實際執行不會發生在你發起它的同一個線程中。在我們所有的例子中,我們只是在主線程中定義了未來,然後在導入的執行上下文中的一個線程中執行了它。

1

慣用方法是不阻止結果。相反,你應該使用地圖/理解和類似的東西來鏈接期貨。

對於flatMaps,maps和withFilters而言,理解僅僅是語法糖,具體取決於您如何使用它。

這不僅是儘可能無阻塞,但它允許您編寫「快樂的道路」,而不是儘可能晚地處理故障。

像Play這樣的許多框架可以讓您永遠不會阻止未來完成並允許您將Futures返回給調用者,並且Framework將爲您處理它。

如果你必須處理展開的未來,你可能想使用onComplete

退房The Neophytes Guide to Scala對於學習這個東西一個很好的教程。