要避免 C# 中的 Parallel.ForEach
競態條件,您需要確保在并行操作期間對共享資源的訪問是線程安全的。這可以通過以下幾種方式來實現:
lock
語句確保一次只有一個線程可以訪問資源。object lockObject = new object();
Parallel.ForEach(items, item => {
lock (lockObject) {
// 訪問共享資源的代碼
}
});
ConcurrentQueue<T>
、ConcurrentBag<T>
或 BlockingCollection<T>
等,這些數據結構在內部實現了線程安全機制。ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
Parallel.ForEach(items, item => {
queue.Enqueue(item);
});
Interlocked
類提供的原子操作方法,如 Interlocked.Increment
或 Interlocked.Decrement
。int counter = 0;
Parallel.ForEach(items, item => {
Interlocked.Increment(ref counter);
});
int numOfPartitions = Environment.ProcessorCount;
var partitions = Partitioner.Create(items, numOfPartitions);
Parallel.ForEach(partitions, partition => {
foreach (var item in partition) {
// 處理每個分區的代碼
}
});
避免全局狀態:盡量減少全局狀態的使用,因為它可能導致競態條件。如果必須使用全局狀態,請確保對其訪問進行同步。
使用 Parallel LINQ (PLINQ)
:PLINQ 可以讓您以聲明式方式編寫并行代碼,它會自動處理并行性和對共享資源的訪問。
var result = items.AsParallel().Where(item => {
// 過濾條件
}).ToList();
總之,要避免 Parallel.ForEach
的競態條件,關鍵是確保對共享資源的訪問是線程安全的。您可以使用鎖、線程安全的數據結構、原子操作、分區等方法來實現這一目標。