在Parallel.For中使用索引器的正确方法
本文关键字:方法 索引 Parallel For | 更新日期: 2023-09-27 18:02:29
我有一个方法,它基于特定的(Waveform(函数生成(Wavewave(位图(在下面的例子中,我只是使用Math.Sin来简化事情(。到目前为止,这个方法是"串行"的(没有线程(,但使用的一些函数相对耗时,所以我尝试使用Parallel.For
和Parallel.ForEach
,但我想我使用的索引变量一定"损坏"了(或者至少有比我预期的值更大的值(,生成的图形将包含"尖峰"或非邻居点之间的奇怪线。
这里首先是我的串行版本(有效(:
Point[] points = new Point[rect.Width];
byte[] ptTypes = new byte[rect.Width];
for (int i = 0; i < rect.Width; i++)
{
double phase = MathUtil.WrapRad((MathUtil.PI2 / (rect.Width / 1d)) * i);
double value = waveform.ValueAtPhase(phase);
newPoint = new Point(rect.Left + i,
rect.Top + (int) (halfHeight + (value * -1d * halfHeight * scaleY)));
points[i] = newPoint;
if (i == 0)
ptTypes[i] = (byte)PathPointType.Start;
else
ptTypes[i] = (byte)PathPointType.Line;
}
using (GraphicsPath wavePath = new GraphicsPath(points, ptTypes))
{
gph.DrawPath(wavePen, wavePath);
}
正如您所看到的,代码只使用了两个数组(一个用于Points,一个用于PointTypes(,因此只要这些值插入到数组的正确元素中,这些值插入数组的顺序就无关紧要。
下一个例子是使用Parallel
Parallel.For(0, rect.Width,
i =>
{
double phase = MathUtil.WrapRad((MathUtil.PI2 / (rect.Width / 1d)) * i);
double value = Math.Sin(phase);//waveform.ValueAtPhase(phase);
newPoint = new Point(rect.Left + i,
rect.Top + (int)(halfHeight + (value * -1d * halfHeight * scaleY)));
points[i] = newPoint;
if (i == 0)
ptTypes[i] = (byte)PathPointType.Start;
else
ptTypes[i] = (byte)PathPointType.Line;
});
最后,我尝试使用带有Parallel.ForEach循环的Partitioner,但这也没有解决问题:
var rangePartitioner = Partitioner.Create(0, rect.Width);
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
for (int i = range.Item1; i < range.Item2; i++)
{
double phase = MathUtil.WrapRad((MathUtil.PI2 / (rect.Width / 1d)) * i);
double value = Math.Sin(phase);//waveform.ValueAtPhase(phase);
newPoint = new Point(rect.Left + i,
rect.Top + (int)(halfHeight + (value * -1d * halfHeight * scaleY)));
points[i] = newPoint;
if (i == 0)
ptTypes[i] = (byte)PathPointType.Start;
else
ptTypes[i] = (byte)PathPointType.Line;
}
});
Pelle
newPoint = new Point(rect.Left + i, rect.Top + (int)(halfHeight + (value * -1d * halfHeight * scaleY)));
newPoint的作用域不在您的for()
循环中——很可能线程在您到达下一行points[i] = newPoint;
之前正在更新它
更改为var newPoint = ...
否则,您的Parallel.For
看起来不错。
此外,这有不同的行为吗?
Math.Sin(phase);//waveform.ValueAtPhase(phase);
提供ValueAtPhase不会修改任何内容,您应该能够在循环中使用它。