2011-11-24 29 views
8

我有一個演員 - 在其本質上 - 維護一個對象列表。它有三個基本操作:添加,更新和刪除(有時從add方法中調用remove,但不在此處),並使用單個集合。顯然,該支持列表是併發訪問的,添加和刪除呼叫不斷交錯。如何處理對Scala集合的併發訪問?

我的第一個版本使用了ListBuffer,但是我在某處讀到它並不是爲了併發訪問。我沒有得到併發訪問異常,但我確實注意到,從中刪除對象並不總是可行,可能是由於併發性。

我半途將其重寫爲使用var List,但從Scala的默認不可變列表中刪除項目有點痛苦 - 我懷疑它適合併發訪問。

所以,基本問題:我應該在併發訪問情況下使用什麼樣的集合類型,以及它是如何使用的?

(也許繼發性:是演員實際上是一個多線程的實體,或者是,只是我的錯誤觀念,它處理郵件一次一個在單個線程?)

(第三:在Scala中,有什麼收藏類型是最好的插入和隨機訪問(刪除/更新)?)

編輯:對善良響應者:請原諒我遲到的答覆,我做了一個討厭的習慣,拋出一個SO或郵件列表的問題,然後進入下一個問題,暫時忘記原來的問題。

+3

演員一次處理一條消息。演員的併發性來自異步消息處理,而不是來自同時處理多條消息的參與者。 –

+2

您試圖解決的業務問題是什麼? –

+0

@ViktorKlang:我會試着解釋一下。用戶通過REST服務向服務器發送名爲NotificationPlan的模型對象。根據NotificationPlan,會生成一些通知對象,這些通知對象將在未來的某個時刻發回給用戶(以Apple推送通知的形式)。 在這種情況下,具有問題中所述列表的actor在內存中維護一個NotificationPlans列表,以便用戶在最初添加它之後可以更新或刪除他的計劃。 – fwielstra

回答

10

看看scala.collection.mutable.Synchronized * traits/classes。

這個想法是你將Synchronized traits混入常規可變集合中以獲得它們的同步版本。

例如:

import scala.collection.mutable._ 
val syncSet = new HashSet[Int] with SynchronizedSet[Int] 
val syncArray = new ArrayBuffer[Int] with SynchronizedBuffer[Int] 
+11

請不要這樣做,它不會縮放。 –

+9

從Scala 2.11開始,SyncronizedSet已不再使用:通過特徵進行同步已被棄用,因爲它本質上不可靠。考慮java.util.concurrent.ConcurrentHashMap [A​​,Unit]作爲替代。 –

0

我應該在併發訪問情況下使用什麼樣的集合類型,以及如何使用它?

查看@ hbatista的回答。

是演員實際上是一個多線程的實體,或者是,只是我的錯誤觀念,它處理郵件一次一個在單個線程

第二(儘管線程上消息處理可能會改變,所以不要在線程本地數據中存儲任何東西)。這就是演員如何保持其狀態不變的原因。

4

您不需要同步演員的狀態。演員的目標是避免棘手,容易出錯和難以調試的併發編程。

演員模型將確保演員將逐個消費消息,並且您將永遠不會有同一個演員的兩個消費線程消息。

3

Scala的不可變集合適合併發使用。

至於演員,一些事情是保證解釋here Akka文件。

  • 演員發送規則:發送給演員的消息發生在同一演員的接收之前。
  • 演員後續處理規則:其中一個消息的處理髮生在同一個演員處理下一個消息之前。

你不能保證同一個線程處理下一個消息,但是你保證下一個開始之前,在當前消息將完成處理,並在任何給定的時間,只有一個線程執行接收方法。

因此,照顧給定的演員的持久狀態。關於共享數據,據我所知,最好的方法是使用不可變數據結構並儘可能依賴Actor模型。也就是說,「不要通過共享內存進行通信;通過通信共享內存。」