2016-12-29 67 views
3

根據Scala文檔,在Future上不應該進行阻塞。我應該阻止未來 - 斯卡拉

「如前所述,爲了表現和防止死鎖,強烈建議阻止未來,期貨的回調和組合器是使用其結果的首選方式,但是在某些情況下可能需要阻止情況並得到期貨和承諾API的支持。「

在我的程序退出之前,如何確保我的所有期貨都已完成(及其回調已完成)?我通常在我的主要功能結束時使用Await.result來確保所有期貨已經完成。

object ConcurrencyExample extends App { 
val gpf= Future {some operations} 
val ccf = Future{some operations} 


val atbf = for {g <- gpf 
c <- ccf if c == true} yield {some operations} 

//is it OK to use Await? If not, how do I ensure that all Futures have finished 
     ? 
Await.result(atbf,1000 millis) 
} 

問題

  1. 是使用等待錯了嗎?我的代碼不會等待期貨完成,否則
  2. 如果是這樣,有什麼選擇?
  3. 在我的主程序退出之前,我如何確保未來及其回調已完成?

回答

5

是的,你可以Await.result在你的情況。

可以使用Await.result保持主線程活着期貨完成

Becareful與Await.result

注意這同時適用於阿卡和播放應用

Await.result只有在絕對必要時才應該使用。

Await.result阻止它運行的線程,直到給定的持續時間。阻塞線程會浪費寶貴的計算資源,因爲該線程將無法執行任何有用的計算,例如處理算法中的新請求或數字計算等。

所以,儘量避免使用Await.result

但是,我們什麼時候使用它(Await.result)?

這是使用Await.result的典型用例之一。

假設你已經編寫了一個包含主線程的程序,並且主線程中的所有計算都是異步的。現在,一旦你開始主線程內的異步計算。有些人不得不停止現有的主線程,直到異步計算完成,否則程序將停止運行,並且看不到異步計算的結果。

當應用程序開始運行時,有一個非守護線程,其任務是執行main()。除非非守護線程完成,否則JVM不會自行退出。

object Main { 
def main(args: Array[String]): Unit = { 
    import scala.concurrent.Future 
    import scala.concurrent.duration._ 

    val f = Future { //do something } 
    //stop main thread till f completes 
    Await.result(f, 10 seconds) 
} 
} 

未來使用守護線程來運行。所以守護進程線程無法阻止JVM關閉。所以即使非守護線程正在運行,JVM也會關閉。

在上述情況下,除非主線程退出並停止計算,否則無法通過其他方式停止(阻塞)主線程直到計算f完成。

在大多數情況下,你不需要使用mapflatMap就足夠使用Await.result簡單Future組成。使用Await.result(一般而言,所有阻塞代碼)的

風險

暗戰線程的基於事件的模型

在基於事件的模型,你會很快如果阻止需要很長時間返回的代碼,則線程用完。在playframework中,任何阻塞調用都可能會降低應用程序的性能,並且應用程序在線程耗盡時會變得很慢。

在非事件運行內存的機型爲主

在每個請求模型線程。當您阻止需要很長時間退出/退回的呼叫時。

案例1:如果您已修復線程池,則應用程序可能會耗盡線程。情況2:如果您有動態增長的線程池,那麼您的應用程序將遭受過多的上下文切換開銷,並且由於內存中被阻塞的線程太多而導致內存不足。

在所有的情況下,沒有有用的工作是期待等待一些IO或其他事件。

+0

謝謝。是否有替代使用Scala的Future更安全,性能更低的風險(如果我們使用Await)? –

+0

@ManuChadha nope,你必須在這種情況下等待。您可以使用await讓主線保持期貨的完整狀態 – pamu

+0

@ManuChadha另一種方式是使用'非deamon'線來進行期貨交易,但這是不好的做法,不應該被使用。 – pamu