gpt4 book ai didi

c# - C# 中带有共享变量的并行 For 循环

转载 作者:太空狗 更新时间:2023-10-29 21:45:13 26 4
gpt4 key购买 nike

我正在尝试使用并行处理来加速几个嵌套循环,但我在正确使用语法时遇到了问题。我正在尝试计算位图中有多少像素是红色、白色或黑色,我在其他地方的枚举中有这些值。

在串行处理中,我有以下代码,工作正常:

        Bitmap image = new Bitmap(@"Input.png");
var colourCount = new int[3];

for (var x = 0; x < image.Width; x++)
{
for (var y = 0; y < image.Height; y++)
{
switch (image.GetPixel(x, y).ToArgb())
{
case (int)colours.red: colourCount[0]++; break;
case (int)colours.white: colourCount[1]++; break;
case (int)colours.black: colourCount[2]++; break;
default: throw new ArgumentOutOfRangeException(string.Format("Unexpected colour found: '{0}'", image.GetPixel(x, y).ToArgb()));
}
}
}

我已经看到 Microsoft 和 Stackoverflow 的并行 for 循环代码更新共享变量,如下所示:

        Parallel.For<int>(0, result.Count, () => 0, (i, loop, subtotal) =>
{
subtotal += result[i];
return subtotal;
},
(x) => Interlocked.Add(ref sum, x)
);

但是所有示例都使用简单类型(例如 int)作为共享变量,我只是想不出写入我的大小为 3 的数组的语法。我处理这一切都错了吗?

顺便说一句,我知道 GetPixel 与 Bitmap.LockBits 之类的东西相比在性能方面非常慢,我只是想弄清楚并行循环的原理。

最佳答案

您可以使用 Parallel.For 的重载这允许您维护线程本地状态。在这种情况下,我们为生成的每个线程创建一个 int[3] 数组。在并行循环的每次迭代中,我们只更新local 数组,localColourCount。最后,当线程要退出时,我们将每个本地数组的结果聚合到全局数组中,colourCount;然而,由于这是一个共享数据结构,我们在访问它时强制执行互斥。

Bitmap image = new Bitmap(@"Input.png");
var colourCount = new int[3];

Parallel.For(0, image.Width,

// localInit: The function delegate that returns the initial state
// of the local data for each task.
() => new int[3],

// body: The delegate that is invoked once per iteration.
(int x, ParallelLoopState state, int[] localColourCount) =>
{
for (var y = 0; y < image.Height; y++)
{
switch (image.GetPixel(x, y).ToArgb())
{
case (int)colours.red: localColourCount[0]++; break;
case (int)colours.white: localColourCount[1]++; break;
case (int)colours.black: localColourCount[2]++; break;
default: throw new ArgumentOutOfRangeException(
string.Format("Unexpected colour found: '{0}'",
image.GetPixel(x, y).ToArgb()));
}
}
},

// localFinally: The delegate that performs a final action
// on the local state of each task.
(int[] localColourCount) =>
{
// Accessing shared variable; synchronize access.
lock (colourCount)
{
for (int i = 0; i < 3; ++i)
colourCount[i] += localColourCount[i];
}
});

此代码假定 Bitmap.GetPixel 是线程安全的,情况可能是也可能不是。

您需要注意的另一件事是任何 ArgumentOutOfRangeException 实例都将合并为 AggregateException,因此您需要调整错误处理代码。

关于c# - C# 中带有共享变量的并行 For 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17118381/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com