并行 C#

Parallel For c#

我正在尝试提高计算图像平均值的方法的性能。

为此,我使用了两个 For 语句来迭代所有图像,因此我尝试使用一个 Parallel For 来改进它,但结果并不相同。

我做错了吗?或者是什么造成了差异?

public static double MeanDN(this GrayImage image)
{
  double mean = 0;
  int totalPixels = image.Width * image.Height;

  for (int i = 0; i < image.Height; i++)
      for (int j = 0; j < image.Width; j++)
          mean += (double)image[i, j] / totalPixels;

  double parallelMean = 0;

  Parallel.For(0, image.Height, i =>
  {
      for (int j = 0; j < image.Width; j++)
          parallelMean += (double)image[i, j] / totalPixels;
  });

  return mean;
}

输出:

mean = 404.12

parallelMean = 148.8658

您正在访问资源(变量 parallelMean),但没有从多个线程进行同步。有些更改会相互覆盖,有些读取会读取错误或旧数据。这就是您看到错误结果的原因。

最简单的解决方案是在对该变量的写访问周围放置一个 lock 语句,但这会迫使它返回顺序进行。

如果您需要对结果进行计算,使用 PLinq 可能会更容易,它会为您完成大部分同步工作:

var mean = Enumerable.Range(0, image.Height)
                     .AsParallel()
                     .Select(i => Enumerable.Range(0, image.Width)
                                            .AsParallel()
                                            .Sum(j => (double)image[i, j] / totalPixels))
                     .Sum();

你的问题是你让多个任务修改同一个变量parallelMean。所以你有一个竞争条件
我还认为第二个结果不仅是错误的,而且还不稳定:意思是再次尝试执行代码,第二个结果会改变
我认为这段代码可以解决您的问题

double[] parallelMean = new double[image.Height];

Parallel.For(0, image.Height, i =>
{
    for (int j = 0; j < image.Width; j++)
        parallelMean[i] += (double)image[i, j] / totalPixels;
});

return parallelMean.Sum();