Как и другие упомянутые ответы, обновление переменной sum
из нескольких потоков (что и делает Parallel.ForEach) не является потокобезопасной операцией.Тривиальное исправление получения блокировки перед обновлением исправит эту проблему .
double sum = 0.0;
Parallel.ForEach(myCollection, arg =>
{
lock (myCollection)
{
sum += ComplicatedFunction(arg);
}
});
Однако это создает еще одну проблему.Поскольку блокировка получается на каждой итерации, это означает, что выполнение каждой итерации будет эффективно сериализовано.Другими словами, было бы лучше просто использовать простой старый цикл * 1007. *.
Теперь, хитрость в получении этого права состоит в том, чтобы разделить проблему на отдельные и независимые блоки.К счастью, это очень легко сделать, когда все, что вы хотите сделать, это суммировать результат итераций, потому что операция суммирования коммутативна и ассоциативна, а промежуточные результаты итераций независимы.
Итак, вот как высделай это.
double sum = 0.0;
Parallel.ForEach(myCollection,
() => // Initializer
{
return 0D;
},
(item, state, subtotal) => // Loop body
{
return subtotal += ComplicatedFunction(item);
},
(subtotal) => // Accumulator
{
lock (myCollection)
{
sum += subtotal;
}
});