Parallel.ForEach on List <Object> Безопасность потоков

Насколько Thread Safety идет, это нормально делать или мне нужно использовать другую коллекцию?

        List<FileMemberEntity> fileInfo = getList(); 

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

Ответы

Ответ 1

Пока вы только изменяете содержимое элемента, переданного методу, блокировки не требуется.

(Разумеется, в списке нет дублирующихся ссылок, т.е. двух ссылок на один и тот же экземпляр 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
});

Ответ 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

Ответ 4

Если неважно, в каком порядке действуют объекты FileMemberEntity, вы можете использовать List<T>, потому что вы не изменяете список.

Если вы должны обеспечить какой-то порядок, вы можете использовать OrderablePartitioner<T> как базовый класс и реализовать соответствующую схему секционирования. Например, если FileMemberEntity имеет какую-то категоризацию, и вы должны обрабатывать каждую из категорий в определенном порядке, вы хотите пойти по этому маршруту.

Гипотетически, если у вас

Объект 1 Категория A

Объект 2 Категория A

Объект 3 Категория B

нет гарантии, что Object 2 Category A будет обработан до того, как Object 3 Category B будет обработан при повторении a List<T> с помощью Parallel.ForEach.

Документация MSDN, на которую вы ссылаетесь, дает пример того, как это сделать.