Parallel.For循环填充List元素数量不足的原因及解决方案
问题原因与解决方法
原因
List<T>不是线程安全的集合,它的Add方法内部包含多个非原子操作:比如检查内部数组容量、写入新元素、更新计数。当多个线程同时调用Add时,会触发竞态条件——例如两个线程同时读取当前的元素计数,然后都基于这个计数去写入新元素,导致其中一个元素的写入被覆盖;或者计数更新时出现错误,最终导致集合内的元素数量少于预期。
正确解决方法
方法1:使用线程安全集合ConcurrentBag<T>
ConcurrentBag<T>是.NET专门为并行场景设计的线程安全集合,适合这种多线程添加元素的场景:
var someBag = new ConcurrentBag<ListItem>(); Parallel.For(0, 1000000, _ => { var item = new ListItem(); // some logic here someBag.Add(item); }); System.Console.WriteLine(someBag.Count); // 输出1000000
如果最终需要List<T>类型,可以在并行操作结束后转换:
var someList = someBag.ToList();
方法2:用锁同步Add操作(不推荐)
虽然可以通过lock关键字确保Add操作的原子性,但这种方式会让并行操作退化为串行执行,完全失去Parallel.For的性能优势,仅适合极端场景:
var someList = new List<ListItem>(); var lockObj = new object(); Parallel.For(0, 1000000, _ => { var item = new ListItem(); // some logic here lock (lockObj) { someList.Add(item); } }); System.Console.WriteLine(someList.Count); // 输出1000000
内容的提问来源于stack exchange,提问作者Egor Shoba
相关产品推荐
相关产品推荐

