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的不同或相同的副本吗?

parallel foreach是否在其中创建函数的不同副本?

由于多个线程同时访问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函数。