2015-07-10 53 views
0

MyProcessingActor演員將在一個實體ID使用ConsistentHashingRouter,使得可以存在這個演員在進程的多個實例在任一個時刻(在多個線程)阿卡:橫跨主角實例共享狀態

的路由演員使用地圖來執行一些計算邏輯。因此,2個不同的演員實例可以同時讀寫這張地圖。

在這些actor實例之間共享映射看起來像是對actor模型的公然違反,即使它是Java ConcurrentHashMap

處理這類問題的最佳選擇是什麼?我沒有看到它在Akka文檔中解決,除非我錯過了這一點。

我可以看到2個選項:

  1. 一個MyMapManagerActor將管理讀/寫此地圖的一個實例。如果這是單線程的,雖然那麼有效MyProcessingActor將單線程以及
  2. 使用阿卡STM的 - 我不認爲這雖然在該項目的最新版本

還有哪些其他的推薦辦法呢?

+0

我沒有很多阿卡的經驗,但一直在研究它。你所描述的似乎與Akka打算適應的範式非常相反。也許你可以在消息中傳遞路由映射並使其不可變。如果你通過它,地圖也應該不可變。 – aglassman

+1

你看過Akka Agents嗎?他們可能有助於解決這類問題http://doc.akka.io/docs/akka/snapshot/java/agents.html – nickebbitt

回答

0

不幸的是,在阿卡看來這似乎是一件相當困難的事情。創建一個actor來管理對地圖的訪問非常麻煩,並且STM在最新版本中似乎不被支持。

因此,此處的解決方案是仔細選擇ConsistentHashingRouter的密鑰,以便從地圖讀取和寫入地圖時不會有任何競爭條件。有問題的地圖是ConcurrentHashMap

-3

如果地圖是Actor實例上的字段,那麼將會有兩個地圖,並且不會發生跨線程問題。如果地圖是共享但只讀的,那麼你仍然可以。如果映射是共享的並且兩個參與者都寫入它,那麼您肯定需要使用ConcurrentHashMap進行鎖定。

+0

您在這裏沒有真正回答這個問題,只是重複了已經提到的問題。 「還有什麼其他推薦的方法?」 – aglassman

+0

這是正確的。我指出的是,如果地圖不被共享,則不存在衝突。所以沒有必要採用其他方法。如果地圖要共享,那麼ConcurrentMap將是正確的選擇。 – Zagrev

+0

這些是共享的:因此,2個不同的演員實例可以同時讀寫這張地圖。 – DJ180

2

正如你在你的問題中所說的,在演員之間共享可變狀態是一件非常糟糕的事情。我已經使用了您提到的兩種方法(使用類似MapManagerActor和使用Akka STM),兩者都可以工作,但MapManagerActor方法對我來說感覺更好。就MapManagerActor而言,序列化的唯一部分是對Map的實際讀取和寫入,而不是計算本身,因此根據您的使用情況,您可能會發現並行化已足夠。

另一種選擇是用Actors替換地圖本身。您可以讓一個父代演員管理這些孩子,以及該演員每個地圖項的一個孩子。如果您的密鑰集是靜態的,則可以在啓動時預先創建所有子Actor,例如使用密鑰(或其哈希碼)作爲actor名稱。然後您可以使用actorSelection直接訪問子Actor,如/user/parentActor/<key>。如果演員需要動態創建,最好向父代演員詢問某個特定的孩子,然後讓其回覆ActorRef給該孩子(如果需要,可以創建該孩子)。喜歡的東西:

override def receive = { 
    case GetActor(key) => 
    context.children(key) match { 
     case Some(ref) => sender ! GetActorReply(ref) 
     case None => sender ! context.actorOf(ChildActor.props, key) 
    } 
    } 
} 

MyProcessingActor然後可以使用ActorRef其所有處理。

0

當Actor實際運行時,它在某個Executor上作爲Runnable運行。按順序運行一組合作演員的技巧是爲每個這樣的演員提供一個專用的串行執行器 - 參見my answer to the corresponding question