使用一次性对象时,尝试并行处理多个任务(或运行时感觉合适)时遇到了一个问题。在下面的代码片段中,每个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/