使用一次性对象时,尝试并行处理多个任务(或运行时感觉合适)时遇到了一个问题。在下面的代码片段中,每个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保存在列表中),然后处置Processorforeach循环完成后,您(异步)等待所有操作完成。

在第二个示例中,当您执行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/

10-13 01:14