Код: Выделить всё
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);
}
Однако результаты довольно большие и занимают много памяти.
Я хотел бы обрабатывать элементы по порядку, как, например. четыре потока запускаются и работают над элементами 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
...
Подробнее о выполненной работе:
Я обрабатываю изображение в оттенках серого, и мне нужно извлечь информацию для каждого «слоя» (элементов в приведенном выше примере), поэтому я перехожу от 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 || y == Height - 1) && inLine)
{
result.AddEnd(x, y-1);
inLine = false;
}
}
}
result_array[i] = result;
});
foreach (object res in resultArray)
{
sequentiallySaveResult(res);
}
Если запускаются 4 потока, начать обработку слоев 1-4, и когда поток завершается, начинает обрабатывать уровень 5, следующий уровень 6 и так далее, результаты будут приходить более или менее в том же порядке, и я могу начать записывать результаты в файл и удалять их из памяти.
Подробнее здесь: https://stackoverflow.com/questions/626 ... rallel-for
Мобильная версия