And*_*nes 6 c# parallel-processing .net-4.5
我正在尝试使用并行处理来加速几个嵌套循环,但我无法正确获得语法.我试图计算一个位图中有多少像素是红色,白色或黑色,我在其他地方枚举的值.
在串行处理中,我有以下代码,工作正常:
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()));
}
}
}
Run Code Online (Sandbox Code Playgroud)
我已经看到Microsoft和来自Stackoverflow的并行for循环代码,它们更新了一个共享变量,如下所示:
Parallel.For<int>(0, result.Count, () => 0, (i, loop, subtotal) =>
{
subtotal += result[i];
return subtotal;
},
(x) => Interlocked.Add(ref sum, x)
);
Run Code Online (Sandbox Code Playgroud)
但是所有的例子都使用一个简单的类型,比如int作为共享变量,我只是想不出写入我的size三个数组的语法.我接近这一切都错了吗?
顺便说一句,我知道GetPixel在性能方面与Bitmap.LockBits相比非常慢,我只是想让并行循环的原理正确.
Parallel.For您可以使用允许您维护线程本地状态的重载。在本例中,我们int[3]为生成的每个线程创建一个数组。在并行循环的每次迭代中,我们仅更新本地数组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];
}
});
Run Code Online (Sandbox Code Playgroud)
此代码假定Bitmap.GetPixel是线程安全的,但情况可能是也可能不是。
您需要注意的另一件事是任何ArgumentOutOfRangeException实例都会合并到一个 中AggregateException,因此您需要调整错误处理代码。