Правильный способ гарантировать потокобезопасность при добавлении в список с использованием библиотеки Parallel

Я перебираю массив строк подключения и в каждом цикле извлекаю некоторую информацию и добавляю ее в список. Теперь я хочу использовать библиотеку Parallel, чтобы сделать ее многопоточной, но я не уверен, гарантирует ли библиотека, что запись в список будет потокобезопасной, или мне нужно использовать блокировку:

List<SomeType> list = new List<SomeType>();

settings.AsParallel().ForAll(setting => 
{
    list.AddRange(GetSomeArrayofSomeType(setting)); /// DO I NEED TO DO LOCKING HERE???
})

person Andrey    schedule 09.01.2012    source источник
comment
Почему бы вам просто не избежать этой сложности в первую очередь и предварительно выбрать параметры, которые будут добавлены в list?   -  person cwharris    schedule 10.01.2012
comment
Я не добавляю настройки в список, я получаю некоторый массив для каждой настройки и добавляю содержимое этого массива в основной список. Извлечение может быть длительным процессом, поэтому мне нужна многопоточность   -  person Andrey    schedule 10.01.2012


Ответы (1)


Запись в список действительно небезопасна для многопоточной записи. Вам нужно либо использовать lock для синхронизации доступа, либо использовать коллекцию, подобную ConcurrentQueue, которая предназначена для многопоточного доступа.

Пример блокировки (при условии, что list является локальным методом)

List<SomeType> list = new List<SomeType>();
settings.AsParallel().ForAll(setting => { 
  lock (list) {
    list.AddRange(GetSomeArrayofSomeType(setting)); 
  }
});

Или еще лучше используйте SelectMany вместо ForEach

var list = settings
  .AsParallel()
  .SelectMany(setting => GetSomeArrayOfSomeType(setting))
  .ToList();
person JaredPar    schedule 09.01.2012
comment
Также хорошо работать, когда каждая задача записывает в свой собственный список (безопасно, поскольку только один поток видит каждый список), а затем объединяет их все на последнем шаге. Это может выиграть, потому что для первой группы добавлений не требуется синхронизации. - person Jon Hanna; 10.01.2012
comment
+1 для SelectMany, следует избегать образца ForAll/lock, так как это приведет к большому количеству конфликтов между рабочими потоками. - person Drew Marsh; 11.01.2012