【问题标题】:async/await WhenAll on two methods with the same return type具有相同返回类型的两个方法上的 async/await WhenAll
【发布时间】:2015-07-07 06:51:14
【问题描述】:

我正在尝试将文件异步上传到 S3 存储桶。我可以使用以下代码成功地做到这一点。

我似乎无法弄清楚如何同时处理两个具有相同返回类型的不同方法。

UploadImagesUploadAttachments 都返回 IEnumerableEntityUploadResult。如何并行执行它们并在它们都完成后返回结果?

public async Task<List<EntityUploadResult>> BulkUploadFiles(IEnumerable<BulkUploadFile> files)
{
    var results = new List<EntityUploadResult>();

    var images = UploadImages(files.Where(x => x.FileType == BulkFileType.Image).AsEnumerable());
    var attachments = UploadAttachments(files.Where(x => x.FileType == BulkFileType.Attachment).AsEnumerable());

    results.AddRange(await images);
    results.AddRange(await attachments);

    return results;
}

private async Task<IEnumerable<EntityUploadResult>> UploadImages(IEnumerable<BulkUploadFile> files)
{
    return await Task.WhenAll(files.Select(i => UploadImage(i)));
}

private async Task<IEnumerable<EntityUploadResult>> UploadAttachments(IEnumerable<BulkUploadFile> files)
{
    return await Task.WhenAll(files.Select(i => UploadAttachment(i)));
}

【问题讨论】:

    标签: c# .net asynchronous async-await


    【解决方案1】:

    首先,这就是您已经在做的事情,即开始这两个操作,然后才等待它们。

    但是,如果您想使用 Task.WhenAll 执行此操作并且只等待一次,您可以使用返回值,该返回值是所有操作返回值的集合,并将它们与 SelectMany 结合起来

    public async Task<List<EntityUploadResult>> BulkUploadFiles(IEnumerable<BulkUploadFile> files)
    {
        var images = UploadImages(files.Where(x => x.FileType == BulkFileType.Image).AsEnumerable());
        var attachments = UploadAttachments(files.Where(x => x.FileType == BulkFileType.Attachment).AsEnumerable());
    
        var results = await Task.WhenAll(images, attachments);
        return results.SelectMany(_ => _).ToList();
    }
    

    【讨论】:

      【解决方案2】:

      await 与他们一起在WhenAll 上,然后稍后检查Result 或通过WhenAll 的返回结果(如本例):

      如果两种类型不同,您可以这样做(如果类型相同,也可以选择);

      await Task.WhenAll(images, attachments);
      var imgResult = images.Result;
      var attResult = attachments.Result;
      

      当它们属于同一类型时,您也可以这样做:

      IEnumerable<IEnumerable<EntityUploadResult>> = await Task.WhenAll(images, attachments);
      

      因此你的台词:

      results.AddRange(await images);
      results.AddRange(await attachments);
      

      可以替换为:

      results.AddRange((await Task.WhenAll(images, attachments)).SelectMany(u => u));
      

      【讨论】:

      • 一个小提示:Result 会将所有异常包装在AggregateException 中,而await 更自然地抛出原始异常类型。出于这个原因,我更喜欢await 而不是Result,即使对于已完成的任务。
      • @StephenCleary 是的,但由于 await Task.WhenAll(…) 本身就是这样做的,所以它要么在那个时候抛出(解包),否则如果我们通过它 Result 将返回已经 -没有投掷就获得了结果。
      猜你喜欢
      • 1970-01-01
      • 2017-12-20
      • 2016-03-08
      • 2016-05-13
      • 1970-01-01
      • 2016-12-12
      • 1970-01-01
      • 2020-08-26
      • 2014-11-01
      相关资源
      最近更新 更多