簡體   English   中英

Scala中的Akka和第三方Java庫的最佳實踐

[英]Best practices with Akka in Scala and third-party Java libraries

我需要在我的Scala / Akka代碼中使用memcached Java API 此API為您提供同步和異步方法。 異步的返回java.util.concurrent.Future 這里有一個關於在Scala中處理Java Futures的問題如何在Akka Future中包裝java.util.concurrent.Future? 但在我的情況下,我有兩個選擇:

  1. 在將來使用同步API和包裝阻止代碼並標記阻塞:

     Future { blocking { cache.get(key) //synchronous blocking call } } 
  2. 使用異步Java API並在Java Future上每隔n ms輪詢一次以檢查未來是否已完成(如上面鏈接問題中的上述答案之一所述)。

哪一個更好? 我傾向於第一種選擇,因為輪詢可以極大地影響響應時間。 不應該blocking { }阻止阻止整個池?

我總是選擇第一個選項。 但我這樣做的方式略有不同。 我不使用blocking功能。 (實際上我還沒有考慮過它。)相反,我正在為Future提供一個包裝同步阻塞調用的自定義執行上下文。 所以看起來基本上是這樣的:

val ecForBlockingMemcachedStuff = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(100)) // whatever number you think is appropriate
// i create a separate ec for each blocking client/resource/api i use

Future {
    cache.get(key) //synchronous blocking call
}(ecForBlockingMemcachedStuff) // or mark the execution context implicit. I like to mention it explicitly.

因此,所有阻塞調用都將使用專用的執行上下文(= Threadpool) 因此它與主要執行上下文分開,負責非阻塞內容。

這種方法也在Typesafe提供的Play / Akka在線培訓視頻中進行了解釋。 第4課中有一個關於如何處理阻塞呼叫的視頻。 它由Nilanjan Raychaudhuri解釋(希望我拼寫正確),他是Scala書籍的着名作者。

更新:在推特上與Nilanjan進行討論 他解釋了blocking方法和自定義ExecutionContext之間的區別。 blocking功能只是創建一個特殊的ExecutionContext 它提供了一個簡單的方法來解決您需要多少線程的問題。 每當池中所有其他現有線程都忙時,它就會生成一個新線程。 所以它實際上是一個不受控制的 ExecutionContext。 它可能會創建大量線程並導致內存不足錯誤等問題 因此,具有自定義執行上下文的解決方案實際上更好,因為它使這個問題變得明顯。 Nilanjan還補充說,你需要考慮電路中斷,因為這個池會因請求而過載。

TLDR:是的,阻止呼叫很糟糕。 使用自定義/專用ExecutionContext來阻止調用。 還要考慮斷路。

Akka文檔提供了一些關於如何處理阻塞調用的建議:

在某些情況下,進行阻塞操作是不可避免的,即讓線程在不確定的時間內進入休眠狀態,等待外部事件發生。 示例是傳統的RDBMS驅動程序或消息傳遞API,其根本原因通常是(網絡)I / O在封面下發生。 面對這種情況時,您可能想要將阻塞調用包裝在Future中並改為使用它,但這種策略太簡單了:當應用程序運行增加時,您很可能會發現瓶頸或內存或線程耗盡加載。

“阻塞問題”的適當解決方案的非詳盡清單包括以下建議:

  • 在一個actor(或由路由器管理的一組actor)中進行阻塞調用,確保配置一個專用於此目的或足夠大小的線程池。

  • 在Future中進行阻塞調用,確保在任何時間點對此類調用的數量進行上限(提交此類無限數量的任務將耗盡您的內存或線程限制)。

  • 在Future中執行阻塞調用,提供一個線程池,其中包含適用於運行應用程序的硬件的線程數上限。

  • 專門用於管理一組阻塞資源(例如,驅動多個通道的NIO選擇器)並在事件消息發生時調度事件。

第一種可能性特別適用於本質上是單線程的資源,例如數據庫句柄,傳統上一次只能執行一個未完成的查詢並使用內部同步來確保這一點。 一種常見的模式是為N個actor創建路由器,每個actor包含一個數據庫連接並處理發送到路由器的查詢。 然后必須調整數量N以獲得最大吞吐量,這將取決於在哪個硬件上部署哪個DBMS。

暫無
暫無

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

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