kim*_*l42 2 c# asynchronous task-parallel-library tpl-dataflow
我目前正在使用 ActionBlock 来处理连续启动的异步作业。它非常适合处理发布到它的每个项目,但无法收集每个作业的结果列表。
我可以使用什么来以线程安全的方式收集工作结果?
我的代码目前是这样的:
var actionBlock = new ActionBlock<int> (async i => await Process(i));
for(int i = 0; i < 100; i++)
{
actionBlock.Post(i);
}
actionBlock.Complete();
await actionBlock.Completion;
Run Code Online (Sandbox Code Playgroud)
我尝试使用 TransformBlock 代替,但在等待完成时它会无限期地挂起。完成状态为“WaitingForActivation”。
我的 TransformBlock 代码是这样的:
var transformBlock = new TransformBlock<int, string> (async i => await Process(i));
for(int i = 0; i < 100; i++)
{
actionBlock.Post(i);
}
actionBlock.Complete();
await actionBlock.Completion;
transformBlock.TryReceiveAll(out IList<string> strings);
Run Code Online (Sandbox Code Playgroud)
事实证明 ConcurrentBag 就是答案
var bag = new ConcurrentBag<string>();
var actionBlock = new ActionBlock<int> (async i =>
bag.Add(await Process(i))
);
for(int i = 0; i < 100; i++)
{
actionBlock.Post(i);
}
actionBlock.Complete();
await actionBlock.Completion;
Run Code Online (Sandbox Code Playgroud)
现在“bag”中包含了所有结果,并且可以作为 IEnumerable 进行访问。
我实际上最终使用的代码使用 Parallel.ForEach 而不是 ActionBlock。
Parallel.ForEach
(
inputData,
i => bag.Add(await Process(i))
);
Run Code Online (Sandbox Code Playgroud)
这要简单得多,但似乎对性能也很好,并且仍然可以选择限制并行度等。