我有一个简单的并行循环做事,然后我将结果保存到一个文件中。
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 是否可以按给定顺序处理项目?我当然可以使用 a 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);
}
而且我还想启动一个线程进行保存,检查接下来需要写入的项目是否可用,写入它,从内存中丢弃。为此,最好按顺序开始处理,以便结果大致按顺序到达。如果第 5 层的结果是倒数第二个,我必须等待写第 5 层(以及所有后续)直到最后。
如果启动 4 个线程,开始处理第 1-4 层,当一个线程完成后,开始处理第 5 层,下一个第 6 层等等,结果将或多或少以相同的顺序出现,我可以开始将结果写入文件并从内存中丢弃它们。