Al igual que las otras respuestas mencionadas, la actualización de la variable sum
de varios subprocesos (que es lo que hace Parallel.ForEach) no es una operación segura para subprocesos. La solución trivial de adquirir un bloqueo antes de realizar la actualización solucionará ese problema.
double sum = 0.0;
Parallel.ForEach(myCollection, arg =>
{
lock (myCollection)
{
sum += ComplicatedFunction(arg);
}
});
Sin embargo, que introduce otro problema. Dado que el bloqueo se adquiere en cada iteración, eso significa que la ejecución de cada iteración se serializará efectivamente. En otras palabras, hubiera sido mejor usar un simple loop viejo foreach
.
Ahora, el truco para hacer esto bien es dividir el problema en mandriles separados e independientes. Afortunadamente, es muy fácil hacerlo cuando todo lo que desea hacer es sumar el resultado de las iteraciones porque la operación suma es conmutativa y asociativa, y porque los resultados intermedios de las iteraciones son independientes.
Así que aquí está cómo lo haces.
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;
}
});
Ver [ incremento de un valor de conteo fuera de alcance parallel.foreach ] (http://stackoverflow.com/questions/2394447/increment-a-count-value-outside-parallel-foreach-scope). Básicamente, puede usar [Interlocked] (http://msdn.microsoft.com/en-us/library/55dzx06b.aspx) si lo necesita, pero es mejor evitar los efectos secundarios si es posible. –