在C#中,對於多執行緒環境下的集合操作,使用
Concurrent
集合(如
ConcurrentDictionary<TKey, TValue>
)通常比使用手動
lock
來實作分區集合的效率更高。下面是詳細的解釋和比較。
分區集合(Partitioned Collections)L
ock
分區集合是一種將集合分割成多個部份,每個部份有自己的鎖,這樣可以減少鎖的競爭,提高並行效能。實作分區集合需要手動管理多個鎖和分區邏輯,這通常會增加程式碼復雜度。
範例:使用分區和
lock
實作執行緒安全集合
public classPartitionedDictionary<TKey, TValue>
{
private readonly int _partitionsCount;
private readonly object[] _locks;
private readonly Dictionary<TKey, TValue>[] _partitions;
publicPartitionedDictionary(int partitionsCount)
{
_partitionsCount = partitionsCount;
_locks = new object[partitionsCount];
_partitions = new Dictionary<TKey, TValue>[partitionsCount];
for (int i = 0; i < partitionsCount; i++)
{
_locks[i] = new object();
_partitions[i] = new Dictionary<TKey, TValue>();
}
}
privateintGetPartitionIndex(TKey key)
{
return (key.GetHashCode() & int.MaxValue) % _partitionsCount;
}
publicvoidAddOrUpdate(TKey key, TValue value)
{
int index = GetPartitionIndex(key);
lock (_locks[index])
{
_partitions[index][key] = value;
}
}
publicboolTryGetValue(TKey key, out TValue value)
{
int index = GetPartitionIndex(key);
lock (_locks[index])
{
return _partitions[index].TryGetValue(key, out value);
}
}
}
Concurrent
集合
Concurrent
集合,如
ConcurrentDictionary<TKey, TValue>
,是由 .NET 提供的內建執行緒安全集合。它們使用了細粒度鎖和無鎖演算法來實作高效的並行操作。這些集合經過高度最佳化,能在高並行環境中提供良好的效能。
範例:使用
ConcurrentDictionary
ConcurrentDictionary<int, string> dictionary = new ConcurrentDictionary<int, string>();
// 添加或更新元素
dictionary.AddOrUpdate(1, "value1", (key, oldValue) => "newValue");
// 讀取元素
if (dictionary.TryGetValue(1, outstringvalue))
{
Console.WriteLine(value);
}
比較
效能 :
Concurrent
集合
:通常在高並行場景下效能更好,因為它們使用了更細粒度的鎖或無鎖演算法,減少了鎖的競爭。
分區集合 +
lock
:雖然分區可以減少鎖競爭,但實作上通常不如
Concurrent
集合最佳化得好,尤其在極高並行下,效能提升有限。
程式碼復雜度 :
Concurrent
集合
:內建實作,使用簡單,程式碼更簡潔,減少了手動管理鎖和分區的復雜性。
分區集合 +
lock
:需要手動實作分區邏輯和管理多個鎖,增加了程式碼復雜性和出錯的可能性。
靈活性和適用場景 :
Concurrent
集合
:適合大多數多執行緒讀寫的場景,特別是當集合操作比較頻繁時。
分區集合 +
lock
:適用於某些特定場景,比如當集合大小固定,或者某些操作對鎖的競爭非常敏感時,但這種情況較少。
結論
在大多數情況下,使用
Concurrent
集合(如
ConcurrentDictionary<TKey, TValue>
)比手動實作分區集合並使用
lock
更高效且簡潔。
Concurrent
集合經過最佳化,能夠提供高效能的並行操作,同時減少了手動管理鎖和分區的復雜性。因此,建議優先考慮使用
Concurrent
集合,只有在非常特殊的需求下,才考慮使用分區集合加
lock
的方式。
ArrayPool使用分區鎖的原因
ArrayPool<T>
是 .NET 提供的用於管理陣列租借和歸還的記憶體池。它使用分區鎖(分段鎖)而不是
Concurrent
集合,主要原因包括效能最佳化和資源管理的需求。以下是具體原因和背景。
1. 效能最佳化
細粒度鎖和無鎖操作
ArrayPool<T>
設計為高效能記憶體池,適用於頻繁的租借和歸還操作。它透過分區鎖實作細粒度釘選,減少了鎖競爭,提升了並行效能。
Concurrent
集合雖然提供了執行緒安全性,但在某些高效能要求的場景下,它的額外開銷可能不如直接使用分區鎖高效。例如,
ConcurrentDictionary
在操作時可能涉及多個內部鎖和復雜的協調機制,這會引入額外的效能開銷。
低延遲需求
ArrayPool<T>
的設計目標是提供低延遲的陣列租借和歸還。透過使用分區鎖,
ArrayPool<T>
可以在大多數情況下避免全域鎖的競爭,從而降低操作延遲。
2. 精細控制資源管理
自訂邏輯和最佳化
ArrayPool<T>
使用分區鎖可以對每個分區套用特定的最佳化和邏輯,這些最佳化可能無法透過通用的
Concurrent
集合實作。例如,
ArrayPool<T>
可以根據特定的分區進行客製化的陣列管理策略,提高資源利用率和回收效率。
分區鎖的實作方式可以針對陣列池的特定需求進行最佳化,如分區的選擇演算法、陣列的管理策略等。這些最佳化是根據
ArrayPool<T>
的使用模式量身客製的。
更好的記憶體管理
ArrayPool<T>
需要在管理記憶體時有更多的控制權。透過分區鎖,可以在每個分區內實作特定的記憶體管理策略,確保在高並行情況下仍然能高效地管理和復用記憶體。
分區鎖允許更精細的記憶體管理,如對不同大小的陣列進行不同的處理,這在
Concurrent
集合中是無法直接實作的。
3. 專用場景的效能優勢
高並行租借和歸還
ArrayPool<T>
的使用場景通常涉及大量高並行的陣列租借和歸還操作。分區鎖可以更好地適應這種高並行需求,透過減少全域釘選,提高整體吞吐量。
使用分區鎖能夠更有效地管理大量的並行請求,將鎖競爭局限在特定的分區內,從而避免全域鎖帶來的效能瓶頸。
範例程式碼
以下是一個簡化的範例,展示
ArrayPool<T>
如何使用分區鎖來管理陣列池:
public classSimpleArrayPool<T>
{
private readonly object[] _locks;
private readonly List<T[]>[] _arrays;
private readonly int _partitions;
publicSimpleArrayPool(int partitions)
{
_partitions = partitions;
_locks = new object[partitions];
_arrays = new List<T[]>[partitions];
for (int i = 0; i < partitions; i++)
{
_locks[i] = new object();
_arrays[i] = new List<T[]>();
}
}
privateintGetPartitionIndex(int length)
{
return (length.GetHashCode() & int.MaxValue) % _partitions;
}
public T[] Rent(int length)
{
int index = GetPartitionIndex(length);
lock (_locks[index])
{
if (_arrays[index].Count > 0)
{
var array = _arrays[index][_arrays[index].Count - 1];
_arrays[index].RemoveAt(_arrays[index].Count - 1);
returnarray;
}
}
returnnew T[length];
}
publicvoidReturn(T[] array)
{
int index = GetPartitionIndex(array.Length);
lock (_locks[index])
{
_arrays[index].Add(array);
}
}
}
總結
ArrayPool<T>
選擇使用分區鎖而不是
Concurrent
集合,主要是出於效能最佳化和資源管理的需求。分區鎖可以提供更高的並行效能和更細粒度的控制,滿足
ArrayPool<T>
的高效能和低延遲需求。透過客製化的最佳化和管理策略,分區鎖在陣列池的使用場景中表現得更加高效。
BeetleX
開源跨平台通訊框架(支持TLS)
提供HTTP,Websocket,MQTT,Redis,RPC和服務閘道器開源元件
個人微信:henryfan128 QQ:28304340
有豐富的高吐網路服務設計經驗
關註公眾號
https://github.com/beetlex-io/