List <object> Thread Safety </object>上的Parallel.ForEach

时间:2012-06-27 17:50:59

标签: c# .net multithreading

就线程安全问题而言,可以做或者我需要使用不同的集合吗?

        List<FileMemberEntity> fileInfo = getList(); 

        Parallel.ForEach(fileInfo, fileMember =>
        {
              //Modify each fileMember 
        }

4 个答案:

答案 0 :(得分:28)

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

(当然,前提是列表中没有重复引用,即对同一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
});

答案 1 :(得分:5)

因为你刚读书,所以你很安全。只是在迭代其项目时​​不要修改列表。

答案 2 :(得分:3)

我们应该使用更少的锁定对象来加快速度。只在Parrallel.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

参考:http://msdn.microsoft.com/en-gb/library/ff963547.aspx

答案 3 :(得分:1)

如果FileMemberEntity个对象的作用顺序无关紧要,可以使用List<T>,因为您没有修改列表。

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

假设你有

  

对象1类别A

     

对象2类别A

     

对象3类别B

在使用Object 2 Category A迭代Object 3 Category B时,无法保证在处理List<T>之前处理Parallel.ForEach

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