C# 如何并行执行有序执行序列。对于?
我有一个简单的并行循环做一些事情,然后我将结果保存到一个文件中C# 如何并行执行有序执行序列。对于?,c#,multithreading,.net-core,seq,concurrent-processing,C#,Multithreading,.net Core,Seq,Concurrent Processing,我有一个简单的并行循环做一些事情,然后我将结果保存到一个文件中 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
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等等
这样,我就可以启动另一个线程,监视数组中下一个需要写入的项(或者当一个项完成时,每个线程都可以发出一个事件),这样我就可以在后面的项仍在处理时开始写入第一个结果,然后释放内存
是否可以并行。按给定顺序处理项目?我当然可以使用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;//已初始化,具有正确的位图
int numLayers=255;
int bitmapWidthPx=10000;
int位图高度px=10000;
object[]resultArray=新对象[numLayer];
对于(0,numLayers,(i)=>
{
对于(int x=0;x
我还想启动一个保存线程,检查下一个需要写入的项目是否可用,写入,从内存中丢弃。对于这一点,如果处理按顺序开始就好了,这样结果就大致按顺序到达。如果第5层的结果排在倒数第二位,我必须等待写入第5层(以及所有后续内容)直到结束
如果4个线程开始,开始处理第1-4层,当一个线程完成后,开始处理第5层,下一个第6层,依此类推,结果或多或少会以相同的顺序出现,我可以开始将结果写入文件并从内存中丢弃它们。如果您想对线程操作进行排序,线程同步101教我们使用条件变量,要在C#任务中实现这些变量,您可以使用提供异步等待函数的
SemaphoreSlim
。再加上一次计数器检查,你会得到想要的结果
但是,我不认为这是必要的,因为如果我理解正确,并且您只想按顺序保存它们以避免将它们存储在内存中,那么您可以使用内存映射文件:
index*size
位置写入缓冲区即可
Parallel
类知道如何并行化工作负载,但不知道如何合并处理的结果。因此,我建议改为使用。您要求以原始顺序保存结果并与处理同时进行,这使得它比通常情况下要复杂一些,但它仍然是完全可行的:
IEnumerable<object> results = Partitioner
.Create(items, EnumerablePartitionerOptions.NoBuffering)
.AsParallel()
.AsOrdered()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
.Select((item, index) => DoStuff(item, index))
.AsEnumerable();
foreach (object result in results)
{
SequentiallySaveResult(result);
}
IEnumerable results=Partitioner
.Create(项,枚举分区选项.NoBuffering)
.天冬酰胺()
.AsOrdered()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
.选择((项目,索引)=>DoStuff(项目,索引))
.AsEnumerable();
foreach(结果中的对象结果)
{
顺序平均结果(结果);
}
说明:
AsEnumerable
。它只是为了表示并行处理的结束。接下来的foreach
将ParallelQuery
视为IEnumerable