C# Parallel.ForEach on List<Object> 线程安全

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11232167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 17:04:05  来源:igfitidea点击:

Parallel.ForEach on List<Object> Thread Safety

c#.netmultithreading

提问by Micah Armantrout

As far as Thread Safety goes is this ok to do or do I need to be using a different collection ?

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

        List<FileMemberEntity> fileInfo = getList(); 

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

采纳答案by Guffa

As long as you are only modifying the contents of the item that is passed to the method, there is no locking needed.

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

(Provided of course that there are no duplicate reference in the list, i.e. two references to the same FileMemberEntityinstance.)

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

If you need to modify the list itself, create a copy that you can iterate, and use a lock when you modify the list:

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

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
});

回答by Henrik

You're safe since you are just reading. Just don't modify the list while you are iterating over its items.

你是安全的,因为你只是在阅读。在迭代其项目时​​不要修改列表。

回答by Eric J.

If it does not matter what order the FileMemberEntityobjects are acted on, you can use List<T>because you are not modifying the list.

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

If you must ensure some sort of ordering, you can use OrderablePartitioner<T>as a base class and implement an appropriate partitioning scheme. For example, if the FileMemberEntityhas some sort of categorization and you must process each of the categories in some specific order, you would want to go this route.

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

Hypothetically if you have

假设你有

Object 1 Category A

Object 2 Category A

Object 3 Category B

对象 1 类别 A

对象 2 类别 A

对象 3 类别 B

there is no guarantee that Object 2 Category Awill be processed before Object 3 Category Bis processed when iterating a List<T>using Parallel.ForEach.

不能保证在迭代using时Object 2 Category A会先处理。Object 3 Category BList<T>Parallel.ForEach

The MSDN documentation you link to provides an example of how to do that.

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

回答by Minh Nguyen

We should use less lock object to make it faster. Only lock object in different local threads of Parrallel.ForEach:

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

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

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