我有一个简单的并行循环来做一些事情,然后我将结果保存到文件中。
object[] items; // array with all items
object[] resultArray = new object[numItems];
Parallel.For(0, numItems, (i) =>
{
object res = doStuff(items[i], i);
resultArray[i] = res;
});
foreach (object res in resultArray)
{
sequentiallySaveResult(res);
}
为了保存,我需要按正确的顺序写入结果。通过将结果放入resultArray
,结果的顺序又正确了。
然而,由于结果相当大并且占用大量内存。
我想按顺序处理这些项目,例如四个线程启动并处理项目 1-4,下一个空闲线程处理项目 5,依此类推。
这样,我可以启动另一个线程,监视数组中接下来需要写入的项目(或者每个线程可以在一个项目完成时发出一个事件),这样我就可以开始写入第一个结果,而后面的项目则被写入仍在处理,然后释放内存。
Parallel.For 是否可以按给定顺序处理项目?我当然可以使用concurentQueue
,将所有索引按正确的顺序放入其中并手动启动线程。
但如果可能的话,我想保留“Parallel.For”实现中关于使用多少线程等的所有自动化。
免责声明:我无法切换到ForEach
,我需要i
.
编辑#1:
目前,执行顺序是完全随机的,一个例子:
Processing item 1/255
Processing item 63/255
Processing item 32/255
Processing item 125/255
Processing item 94/255
Processing item 156/255
Processing item 187/255
Processing item 249/255
...
编辑#2:
已完成工作的更多详细信息:
我处理灰度图像并需要提取每个“层”(上例中的项目)的信息,因此我从 0 到 255(对于 8 位)并对图像执行任务。
我有一个类可以同时访问像素值:
unsafe class UnsafeBitmap : IDisposable
{
private BitmapData bitmapData;
private Bitmap gray;
private int bytesPerPixel;
private int heightInPixels;
private int widthInBytes;
private byte* ptrFirstPixel;
public void PrepareGrayscaleBitmap(Bitmap bitmap, bool invert)
{
gray = MakeGrayscale(bitmap, invert);
bitmapData = gray.LockBits(new Rectangle(0, 0, gray.Width, gray.Height), ImageLockMode.ReadOnly, gray.PixelFormat);
bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(gray.PixelFormat) / 8;
heightInPixels = bitmapData.Height;
widthInBytes = bitmapData.Width * bytesPerPixel;
ptrFirstPixel = (byte*)bitmapData.Scan0;
}
public byte GetPixelValue(int x, int y)
{
return (ptrFirstPixel + ((heightInPixels - y - 1) * bitmapData.Stride))[x * bytesPerPixel];
}
public void Dispose()
{
gray.UnlockBits(bitmapData);
}
}
循环是
UnsafeBitmap ubmp; // initialized, has the correct bitmap
int numLayers = 255;
int bitmapWidthPx = 10000;
int bitmapHeightPx = 10000;
object[] resultArray = new object[numLayer];
Parallel.For(0, numLayers, (i) =>
{
for (int x = 0; x < bitmapWidthPx ; x++)
{
inLine = false;
for (int y = 0; y < bitmapHeightPx ; y++)
{
byte pixel_value = ubmp.GetPixelValue(x, y);
if (i <= pixel_value && !inLine)
{
result.AddStart(x,y);
inLine = true;
}
else if ((i > pixel_value || y == Height - 1) && inLine)
{
result.AddEnd(x, y-1);
inLine = false;
}
}
}
result_array[i] = result;
});
foreach (object res in resultArray)
{
sequentiallySaveResult(res);
}
我还想启动一个线程进行保存,检查接下来需要写入的项目是否可用,写入它,从内存中丢弃。为此,如果处理按顺序开始,以便结果到达,那就太好了roughly为了。如果第 5 层的结果到达倒数第二个,我必须等待写入第 5 层(以及后续所有层)直到最后。
如果有 4 个线程启动,则开始处理第 1-4 层,当一个线程完成后,开始处理第 5 层,下一个第 6 层,依此类推,结果将或多或少以相同的顺序出现,我可以开始将结果写入文件并将其从内存中丢弃。