C# 列表上的Parallel.ForEach<;对象>;线程安全

C# 列表上的Parallel.ForEach<;对象>;线程安全,c#,.net,multithreading,C#,.net,Multithreading,就线程安全而言,这样做可以吗?还是我需要使用不同的集合 List<FileMemberEntity> fileInfo = getList(); Parallel.ForEach(fileInfo, fileMember => { //Modify each fileMember } List fileInfo=getList(); Parallel.ForEach(fileIn

就线程安全而言,这样做可以吗?还是我需要使用不同的集合

        List<FileMemberEntity> fileInfo = getList(); 

        Parallel.ForEach(fileInfo, fileMember =>
        {
              //Modify each fileMember 
        }
List fileInfo=getList();
Parallel.ForEach(fileInfo,fileMember=>
{
//修改每个文件成员
}

由于您只是在阅读,所以您是安全的。只要在迭代列表项时不要修改列表。

如果无论对
FileMemberEntity
对象的操作顺序如何,您都可以使用
list
,因为您没有修改列表

如果您必须确保某种排序,则可以使用
OrderablePartitioner
作为基类并实现适当的分区方案。例如,如果
FileMemberEntity
具有某种分类,并且您必须按特定顺序处理每个类别,则您可能希望采用此方法

假设你有

对象1 A类

对象2 A类

对象3 B类

当使用
Parallel.ForEach
迭代
列表时,不能保证在处理
对象3类别B
之前处理
对象2类别A


您链接到的MSDN文档提供了一个如何执行此操作的示例。

只要您只修改传递给该方法的项的内容,就不需要锁定

(当然,前提是列表中没有重复引用,即对同一
FileMemberEntity
实例的两个引用。)

如果需要修改列表本身,请创建一个可以迭代的副本,并在修改列表时使用锁:

List<FileMemberEntity> fileInfo = getList();

List<FileMemberEntity> copy = new List<FileMemberEntity>(fileInfo);
object sync = new Object();

Parallel.ForEach(copy, fileMember => {
  // do something
  lock (sync) {
    // here you can add or remove items from the fileInfo list
  }
  // do something
});
List fileInfo=getList();
列表副本=新列表(fileInfo);
对象同步=新对象();
Parallel.ForEach(复制,fileMember=>{
//做点什么
锁定(同步){
//在这里,您可以从fileInfo列表中添加或删除项目
}
//做点什么
});

我们应该使用更少的锁对象来提高速度。在Parralel.ForEach的不同本地线程中仅使用锁对象:

List<FileMemberEntity> copy = new List<FileMemberEntity>(fileInfo);
object sync = new Object();

Parallel.ForEach<FileMemberEntity, List<FileMemberEntity>>(
      copy,
      () => { return new List<FileMemberEntity>(); },
      (itemInCopy, state, localList) =>
      {
         // here you can add or remove items from the fileInfo list
         localList.Add(itemInCopy);
         return localList;
      },
      (finalResult) => { lock (sync) copy.AddRange(finalResult); }
); 

 // do something
List copy=新列表(fileInfo);
对象同步=新对象();
并行ForEach(
复制
()=>{返回新列表();},
(itemInCopy、state、localList)=>
{
//在这里,您可以从fileInfo列表中添加或删除项目
localList.Add(itemInCopy);
返回localList;
},
(finalResult)=>{lock(sync)copy.AddRange(finalResult);}
); 
//做点什么

参考:

请保持问题的单一性。您是否修改了foreach循环中的任何内容?如果没有,则可能不关心线程安全。如果您正在修改,则需要执行锁定我是否可以使用其他集合而不需要锁定只要您不修改ist.在不知道您在循环中做什么的情况下,我只能随意猜测我正在修改集合中的项目,只要您不修改实际集合本身就可以了。您不能对其中的项目重新排序,也不能向其中添加或删除项目。因此,如果我在更新列表中的项目,只要我不更新,这并不重要't不更改实际集合?如果您正在修改集合中的对象(而不是集合本身),则我正在修改Foreach中的集合这很好。内容是集合…集合中包含的内容不是正确的吗?@MicahArmantrout:内容是作为
fileMember
传递给该方法的
fileMember
实例中的任何内容。这会使所有其他线程停止,直到其脱离锁或并行.ForEach线程是否会转到列表中的另一项?@MicahArmantrout:锁只会保护锁内的代码不被多个线程同时执行。锁外的代码本身仍然可以同时在多个线程中运行。这不是破坏了并行性的目的吗?在这种情况下不会产生更多的影响使用标准foreach有意义吗?