共用方式為


使用執行緒安全集合的時機

.NET Framework 4 引進了五種集合類型,專為支援多線程新增和移除作業而設計。 為了達到線程安全性,這些類型會使用各種有效率的鎖定和無鎖定同步處理機制。 同步處理會增加作業的額外負荷。 額外負荷取決於所使用的同步處理類型、執行的作業種類,以及嘗試同時存取集合的線程數目等其他因素。

在某些情況下,同步處理的額外負荷微不足道,這使得多執行緒類型在受到外部鎖定保護時,執行速度顯著提高,並且在擴展能力上比其非執行緒安全的同類更佳。 在其他情況下,額外的負荷可能會導致執行緒安全類型的性能和擴展能力大約相同,甚至比使用外部鎖定的非執行緒安全型別版本還要慢。

以下各節提供一般指引,說明何時應使用執行緒安全集合與具有使用者提供的讀取和寫入操作鎖定的非執行緒安全版本相較之下使用的情況。 因為效能可能會因許多因素而有所不同,因此指導方針並不明確,而且在所有情況下都不一定有效。 如果效能非常重要,則判斷要使用的集合類型的最佳方式是根據代表性的計算機組態和負載來測量效能。 本檔案使用下列詞彙:

純生產者-消費者案例
任何指定的線程都是新增或移除元素,但不是兩者。

混合生產者-取用者案例
任何指定的線程都會加入和移除元素。

加速
在相同情境下,該演算法相較於其他類型有更快的效能。

延展性
與計算機上的核心數目成正比的效能增加。 可擴展的演算法在八個核心上的執行速度比在兩個核心上更快。

ConcurrentQueue(T) vs. Queue(T)

在純粹的生產者-消費者案例中,若每個元素的處理時間非常短(僅需一些指令),則 System.Collections.Concurrent.ConcurrentQueue<T> 相較於具有外部鎖定的 System.Collections.Generic.Queue<T>,可以提供適度的效能提升。 在此案例中,當一個專用執行緒入佇列且一個專用執行緒出佇列時,ConcurrentQueue<T> 效能最佳。 如果您未強制執行此規則,則 Queue<T> 甚至可能比具有多個核心的計算機上執行速度 ConcurrentQueue<T> 稍微快一些。

當處理時間大約是 500 FLOPS(浮點運算)或更多時,則雙線程規則不會套用至 ConcurrentQueue<T>,然後具有非常好的延展性。 Queue<T> 在此案例中無法正常調整。

在混合生產者-消費者的場景中,當處理時間非常短時,具有外部鎖定的 Queue<T> 的擴展能力較 ConcurrentQueue<T> 更好。 不過,當運算性能大約是 500 FLOPS 或更多時,則 ConcurrentQueue<T> 的縮放效果會更好。

ConcurrentStack 與 Stack

在純粹的生產者-消費者情境中,當處理時間很短時,System.Collections.Concurrent.ConcurrentStack<T>System.Collections.Generic.Stack<T>具有外部鎖可能會與一個專門的推送執行緒和一個專門的取出執行緒表現大致相同。 不過,隨著線程數目增加,這兩種類型因爭用增加而變慢,而且 Stack<T> 效能可能會優於 ConcurrentStack<T>。 當處理時間約為 500 個 FLOPS 或更多時,這兩種類型會以大約相同的速率進行調整。

在混合生產者-取用者案例中,ConcurrentStack<T> 在小型和大型工作負載下的運行速度更快。

使用 PushRangeTryPopRange 可能會大幅加快存取時間。

ConcurrentDictionary 與 Dictionary

一般而言,在任何您同時從多個線程新增和更新索引鍵或值的情況中,請使用 System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> 。 在涉及頻繁更新和相對較少讀取的案例中,ConcurrentDictionary<TKey,TValue> 會提供適度的好處。 在涉及許多讀取和許多更新的案例中,在具有任意數目核心的計算機上, ConcurrentDictionary<TKey,TValue> 通常較快。

在涉及頻繁更新的案例中,您可以增加 ConcurrentDictionary<TKey,TValue> 的並行程度,然後測量是否在具有更多核心的電腦上能提高效能。 如果您變更並行層級,請盡可能避免全域作業。

如果您只讀取索引鍵或值, Dictionary<TKey,TValue> 則 較快,因為如果字典未由任何線程修改,則不需要同步處理。

ConcurrentBag

在純生產者-取用者案例中, System.Collections.Concurrent.ConcurrentBag<T> 執行速度可能會比其他並行集合類型慢。

在混合生產者-消費者情境中,ConcurrentBag<T> 相較於任何其他並行集合類型,在大型和小型工作負載下通常表現得更快且更具擴充性。

封鎖集合

需要界限和封鎖語意時, System.Collections.Concurrent.BlockingCollection<T> 執行速度可能會比任何自定義實作更快。 它也支援豐富的取消、列舉和例外狀況處理。

另請參閱