2015-07-13 23 views
2

我有一種方法可以根據特定的(波形)函數(在下面的示例中我簡單地使用Math.Sin來簡化事情)生成(波形)位圖。到目前爲止,這種方法是「串行」(沒有線程),但使用的一些功能相對耗時,所以我嘗試使用Parallel.ForParallel.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); 
} 

正如你所看到的代碼只需使用2點陣列(一個點,一個用於PointTypes)所以這些值插入順序數組無關緊要,只要將值插入數組的正確元素即可。

下一頁示例是使用的Parallel.For(爲了簡化實施例I省略了陣列的創建和實際拉制法):

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環,但這並沒有解決問題或者:

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; 
    } 
}); 

佩爾

+0

有什麼問題? –

回答

2
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不修改任何東西,你應該能夠在循環中使用它。

+0

你是絕對嚴格的,並將代碼轉換爲「points [i] = new Point(..」(不使用newPoint)var修復Parallel.For循環(它接縫),然而Parallel.ForEach(使用分區程序)仍然不好!? –

+0

@PelleLiljendal通常Parallel.ForEach用於迭代IEnumerables - 並且每次傳遞給你一個項目,這不是一個很好的候選人,我最好的猜測是'Partitioner.Create(0,rect .Width);''某種方式關閉,''Parallel.ForEach''和'Parallel.For'的行爲方式相同(因爲'for'和'foreach'的行爲方式相同) - 所以這隻表示分區器被破壞。我會堅持使用'Parallel.For',如果你有一個集合,只使用'Parallel.ForEach'。 – Rob

+0

ValueAtPhase應該是線程安全的,但是爲了消除這個問題,我臨時改變了代碼改爲使用Math.Sin –

相關問題