像其他人提到的答案一樣,從多個線程更新sum
變量(這是Parallel.ForEach的作用)不是線程安全操作。在進行更新之前獲取鎖的微小修復將修復即問題。
double sum = 0.0;
Parallel.ForEach(myCollection, arg =>
{
lock (myCollection)
{
sum += ComplicatedFunction(arg);
}
});
然而,這引入了另一個問題。由於鎖是在每次迭代中獲取的,那麼這意味着每次迭代的執行將被有效地序列化。換句話說,使用簡單的舊的foreach
循環會更好。
現在,獲得這一權利的訣竅是將問題分割成獨立的卡盤。幸運的是,當所有你想做的事情總結迭代的結果時,這是非常容易的,因爲和運算是交換和關聯的,並且迭代的中間結果是獨立的。
所以這裏是你如何做到這一點。
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;
}
});
見[ 增量外parallel.foreach範圍 的計數值(http://stackoverflow.com/questions/2394447/increment-a-count-value-outside-parallel-foreach-scope)。基本上,如果需要,您可以使用[Interlocked](http://msdn.microsoft.com/en-us/library/55dzx06b.aspx),但如果可能的話,最好避免使用副作用。 – 2010-07-29 22:03:33