要避免 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
的竞态条件,关键是确保对共享资源的访问是线程安全的。您可以使用锁、线程安全的数据结构、原子操作、分区等方法来实现这一目标。