列出线程安全
我使用以下代码
var processed = new List(); Parallel.ForEach(items, item => { processed.Add(SomeProcessingFunc(item)); });
上面的代码线程安全吗? 处理后的列表是否有可能被破坏? 或者我应该在添加之前使用锁?
var processed = new List(); Parallel.ForEach(items, item => { lock(items.SyncRoot) processed.Add(SomeProcessingFunc(item)); });
谢谢。
没有! 它根本不安全,因为processed.Add
不是。 你可以这样做:
items.AsParallel().Select(item => SomeProcessingFunc(item)).ToList();
请记住, Parallel.ForEach
主要是为序列的每个元素的命令式操作而创建的。 你要做的是map:项目序列的每个值。 这就是为其创建的Select
。 AsParallel
以最有效的方式跨线程缩放它。
此代码正常工作:
var processed = new List(); Parallel.ForEach(items, item => { lock(items.SyncRoot) processed.Add(SomeProcessingFunc(item)); });
但就multithreading而言毫无意义。 lock
每次迭代强制完全顺序执行,一堆线程将等待单线程。
使用:
var processed = new ConcurrentBag();
参见并行foreach循环 – 奇怪的行为 。
在Jon Skeet到达之前引用它:
作为.Net 4中Parellel Extensions的一部分,新的
System.Collections.Concurrent
命名空间中有几个新集合。 这些设计在面对来自多个线程的并发操作时是安全的,锁定相对较少。
这些包括IProducerConsumerCollection
等。
作为安德烈答案的替代方案:
items.AsParallel().Select(item => SomeProcessingFunc(item)).ToList();
你也可以写
items.AsParallel().ForAll(item => SomeProcessingFunc(item));
这使得它后面的查询更加高效,因为不需要合并, MSDN 。 确保SomeProcessingFunc
函数是线程安全的。 而且我认为,但是没有测试它,如果可以在其他线程(添加或删除)元素中修改列表,则仍需要锁定。
使用Something类型的ConcurrentBag
var bag = new ConcurrentBag>; var items = GetAllItemsINeed(); Parallel.For(items,i => { bag.Add(i.DoSomethingInEachI()); });
读取是线程安全的,但添加不是。 您需要读取器/写入器锁定设置,因为添加可能会导致内部arraysresize,从而导致并发读取混乱。
如果你可以保证arrays不会在添加时resize,你可以安全地在阅读时添加,但不要引用我。
但实际上,列表只是数组的接口。
上述就是C#学习教程:列出线程安全分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1004125.html