在使用一次性对象时,我在尝试并行处理多个任务(或者运行时感觉合适)时遇到了问题。在以下代码片段中,每个 Processor 对象在完成所需工作之前立即被释放。
async public Task ProcessData(IEnumerable<int> data)
{
var tasks = new List<Task>();
foreach (var d in data)
{
using (var processor = new Processor(d))
{
processor.Completed += (sender, e) => { // Do something else };
tasks.Add(processor.ProcessAsync());
}
}
await Task.WhenAll(tasks);
}
如下重写代码会导致每个处理器执行其处理然后被处置,但这不是运行多个不依赖于彼此的任务的最有效方式。
async public Task ProcessData(IEnumerable<int> data)
{
foreach (var d in data)
{
using (var processor = new Processor(d))
{
processor.Completed += (sender, e) => { // Do something else };
await processor.ProcessAsync();
}
}
}
有人可以解释一下为什么第一个示例“提前”处理并给出了针对这种情况的最佳代码模式的示例。
最佳答案
这有助于将 await
视为暂停当前的方法,即使它不会阻塞线程。
在你的第一个例子中,当你执行 foreach
循环时,每次你创建一个 Processor
时,开始一个操作(保存操作的 Task
在列表中),然后处理 Processor
。 foreach
循环完成后,您(异步地)等待所有操作完成。
在你的第二个例子中,当你执行 foreach
循环时,每次你创建一个 Processor
,开始一个操作,(异步)等待它完成,然后处理 Processor
。
要解决这个问题,您应该编写一个辅助方法,如下所示:
private static async Task ProcessData(int data)
{
using (var processor = new Processor(d))
{
processor.Completed += (sender, e) => { /* Do something else */ };
await processor.ProcessAsync();
}
}
您的辅助方法定义了一个更高级别的操作,它将负责在适当的时候处理自己的 Processor
资源。然后你就可以同时开始所有的工作了:
public async Task ProcessData(IEnumerable<int> data)
{
...
await Task.WhenAll(data.Select(d => ProcessData(d)));
...
}
关于c# - 对一次性对象使用 Await Async WhenAll,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17797036/