Parallel.ForEach on<Object> list Thread Safety



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

        List<FileMemberEntity> fileInfo = getList(); 
        Parallel.ForEach(fileInfo, fileMember =>
        {
              //Modify each fileMember 
        }

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

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

你很安全,因为你只是在阅读。只是不要在循环访问列表项时修改列表。

我们应该使用更少的锁定对象来使其更快。仅在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

如果操作

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

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

假设你有

对象 1 类别 A

对象 2 类别 A

对象 3 B 类

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

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

最新更新