2011-03-14 70 views
25

由於MSDN saysConcurrentDictionary <TKey,TValue> VS字典<TKey,TValue>

ConcurrentDictionary<TKey, TValue>類表示可以由多個線程同時訪問的鍵值對的線程安全集合。

但我知道,System.Collections.Concurrent類是專爲PLINQ。

我有Dictionary<Key,Value>這使上線的客戶端服務器,我讓線程通過鎖定目標,當我有機會獲得它的安全。

我可以放心地在我的情況下ConcurrentDictionary<TKey,TValue>更換Dictionary<TKey,TValue>?更換後性能會有所提高嗎?

Here在第5部分約瑟夫阿爾巴哈利提到,它設計成用於並行編程

  • 的併發集合被調諧爲並行編程。除了高度併發的場景外,傳統系列的表現都優於它們。
  • 線程安全的集合不保證使用它的代碼是線程安全的。
  • 如果枚舉一個併發收集,而另一個線程正在修改它,則不會拋出異常。相反,您會混合使用新舊內容。
  • List沒有併發版本。
  • 併發堆棧,隊列和包類是內部實現的鏈表。這使得它們的內存效率低於非併發棧和隊列類,但對於併發訪問更好,因爲鏈表有利於鎖定免費或低鎖的實現。 (這是因爲插入節點到鏈表需要更新,只是一對夫婦的參考,同時將元素插入一個列表狀結構可能需要移動目前數以千計的元素。)
+0

我不知道System.Collections.Concurrent類是「爲PLINQ設計的」這個事實 - 你從哪裏得到這個想法? – BrokenGlass 2011-03-14 19:38:52

+0

@BrokenGlass:也許在lambda和匿名類型是「爲LINQ設計」的意義上;他們由於* LINQ而成爲框架*,但他們肯定具有超越它的適用性。 – 2011-03-14 19:40:05

+0

@BrokenGlass和@Adam Robinson,請參閱編輯後文章 – 2011-03-14 20:01:55

回答

16

不知道更多關於你的鎖內做什麼,那麼就很難說。

舉例來說,如果你所有的字典訪問看起來是這樣的:

lock(lockObject) 
{ 
    foo = dict[key]; 
} 

... // elsewhere 

lock(lockObject) 
{ 
    dict[key] = foo; 
} 

然後你會被罰款切換出來(雖然你可能不會看到任何性能上的差異,所以如果艾因不會破壞,不要修復它)。但是,如果您在與字典交互的鎖定塊中執行任何操作,那麼您必須確保字典提供了一個可以完成您在鎖定塊內執行的操作的單個函數,否則你最終會得到與之前功能不同的代碼。要記住的最重要的事情是,字典只保證對字典的併發調用以串行方式執行;它無法處理您在您的代碼中多次與字典進行交互的情況。像這樣的情況,如果沒有被ConcurrentDictionary所解釋,則需要您自己的併發控制。

謝天謝地,ConcurrentDictionaryAddOrUpdateGetOrAdd等更常見的多步操作提供了一些輔助函數,但它們不能涵蓋所有情況。如果你發現自己不得不努力將自己的邏輯變爲這些功能,那麼處理自己的併發可能會更好。

1

您可以ConcurrentDictionary<TKey, TValue>取代Dictionary<TKey, TValue>

對性能的影響可能不是你想要什麼,但(如果有大量的鎖定/同步的,性能可能會受到影響......但至少你的收藏是線程安全的)。

1

雖然我不確定更換困難,但如果你有任何地方,你需要訪問多個元素的字典在同一個「鎖定會話」,那麼你就需要修改你的代碼。

如果微軟已經給讀單獨的鎖和寫它可以給更高的性能,因爲讀操作不會阻礙其他讀取操作。

0

是的,您可以安全地更換,但爲plinq設計的字典可能會有一些額外的代碼,用於您可能不會使用的附加功能。但是性能開銷稍微小一點。

3

這不像將Dictionary替換爲ConcurrentDictionary那麼簡單,您需要修改代碼,因爲這些類具有行爲不同的新方法,以確保線程安全。例如,您不必撥打AddRemove,您有TryAddTryRemove。使用這些原子方法的方法很重要,就好像你打了兩個電話,其中第二個電話依賴於第一個電話的結果,你仍然有競爭條件,需要lock

相關問題