2013-05-30 53 views
26

在scala中使用futures時,默認行爲是使用默認Implicits.global執行上下文。看來這默認爲每個處理器提供一個線程。在更傳統的線程Web應用程序中,當期貨執行諸如等待數據庫的任務(而不是某些cpu綁定任務)時,這似乎是一個糟糕的默認值。我應該重寫默認的ExecutionContext嗎?

我期望重寫默認的上下文在生產中是相當標準的,但是我可以找到關於這麼做的很少的文檔,看起來它可能並不常見。我錯過了什麼嗎?

回答

39

而不是將其視爲重寫默認執行上下文,爲什麼不問問「我應該爲不同的事情使用多個執行上下文?」如果這是問題,那麼我的答案是肯定的。我在哪裏工作,我們使用阿卡。在我們的應用程序中,我們使用默認的Akka執行上下文來實現非阻塞功能。然後,因爲當前沒有好的非阻塞jdbc驅動程序,我們所有的阻塞SQL調用都使用單獨的執行上下文,我們在每個連接方法中都有一個線程。保持主執行上下文(分支連接池)不受阻塞導致我們的吞吐量顯着增加。

我認爲完全可以在系統中爲不同類型的工作使用多個不同的執行上下文。它對我們很好。

+3

+1提到重要的決定因素是您是否在期貨中使用阻塞(或長期運行)代碼。如果你不這樣做,使用單獨的執行上下文實際上是反生產的。 –

+0

如果你想要一個自定義的執行器,你可以控制,但想堅持默認的並行機制和其他參數,似乎'ExecutionContext.fromExecutor(new scala.concurrent.forkjoin.ForkJoinPool)'(不帶參數)似乎做的伎倆;在我的i7上創建了一個包含8個核心(包括超線程)的8個池,它與'ForkJoinPool'匹配。commonPool'包含。 –

+0

@cmbaxter你是否將你的JDBC調用封裝在期貨的'blocking {}中?如果有獨立的ExecutionContext,是否有必要? –

2

是的,在您的應用程序中創建和使用其他執行上下文絕對是一個好主意。

執行上下文將模塊化您的併發模型並隔離應用程序的不同部分,以便在應用程序的某個部分出現問題時,其他部分受此影響較小。考慮你的例子,你將有不同的執行上下文用於特定於數據庫的操作,另一個用於處理Web請求。

在Jonas Boner的this presentation中這種模式被稱爲在您的應用程序中創建「Bulkheads」以獲得更高的穩定性&容錯。

我必須承認,我自己並沒有聽說過有關執行上下文的用法。但是,我確實看到這個原則適用於某些框架。例如,Play將針對不同類型的作業使用不同的執行上下文,並鼓勵您根據需要將您的任務分成不同的池:Play Thread Pools

Akka中間件還建議將您的應用程序分割爲不同併發區域的不同上下文你的申請。他們使用Dispatcher的概念,這是電池的執行環境。

此外,scala併發庫中的大多數運算符都需要執行上下文。這在設計上爲您提供了在模塊化應用程序併發性時所需的靈活性。

+1

Scala中的默認'ExecutionContext'是最新的ForkJoin池。鑑於此,您的陳述表明全球執行環境「適用於小型快速工作,但肯定不會擴展到更大的應用程序」是沒有根據的。 –

+0

這並不是說默認的執行上下文本身並不是高性能的。我的意思是說,在大規模應用程序中只使用一個執行上下文不是最好的。儘管如此,由於混亂,我刪除了該評論。 –

3

「正確的」答案是您的需要使用ExecutionContext的方法需要在其簽名中使用ExecutionContext,因此您可以從「外部」提供ExecutionContext以控制更高級別的執行。

相關問題