parallel foreach是否在其中创建函数的不同副本?
本文关键字:副本 函数 foreach 是否 在其中 创建 parallel | 更新日期: 2023-09-27 18:10:19
我有以下场景,
Parallel.Foreach(al , sentence =>
{
function abc
{
double x;
}
y = Add(ref y, x)
}
public static double Add(ref double location1, double value)
{
double newCurrentValue = 0;
while (true)
{
double currentValue = newCurrentValue;
double newValue = currentValue + value;
newCurrentValue = Interlocked.CompareExchange(ref location1, newValue, currentValue);
if (newCurrentValue == currentValue)
return newValue;
}
}
对于句子al数组中的每个句子,将计算某个x值。我想把所有句子的这些值加到变量y中,但是每次运行代码时,我得到的y值都不同,我猜这是因为x在写入y之前被覆盖了,所以对于每个句子,Parallel Foreach会创建函数abc的不同或相同的副本吗?
由于多个线程同时访问y
进行写操作
例如,以下代码可能不会导致4950
int y=0;
Parallel.ForEach(Enumerable.Range(0, 100), x => y += x);
但是这个保证了
int z = 0;
Parallel.ForEach(Enumerable.Range(0, 100), x => Interlocked.Add(ref z, x));
这是因为y= y+x;
不是线程安全的。用Interlocked.Add
代替
Interlocked.Add(ref y, x);
如前所述,求和/赋值本身不是线程安全的。然而,Interlocked.Add
不能用于双打。这样就留下了锁定的选项,但是,有一种更简单的方法,使用您的伪代码:
var y= al.AsParallel().Select(sentence => function(sentence )).Sum();
使用线程安全的double Sum(this ParallelQuery<double> source)
编辑在您发布的更新代码中,y仍然在多个线程(y = Add(ref y, x)
)中分配,这不是线程安全的。您可以使用上面的建议来代替add函数。