【问题标题】:Find Result of Parallel Async Tasks查找并行异步任务的结果
【发布时间】:2016-02-23 03:34:49
【问题描述】:

基于this question,我正在尝试设置代码以将多个图像并行保存到 Azure Blob 存储。下面的这个方法工作正常,等待 Task.WhenAll(tasks) 在继续之前等待所有完成。

唯一的麻烦是,我希望能够查明每个将信息存储在我们数据库中的请求是否真的成功了。 _db.AddImageAsync 返回一个布尔值,下面的代码等待所有任务完成,但是当我检查所有任务的结果时,每个任务都是假的(即使我实际上在括号内返回了真)。

Enumerable 中的每个任务都表示尚未计算结果,即使我通过断点逐步执行并且每个任务都已执行。

  var tasks = wantedSizes.Select(async (wantedSize, index) =>
  {
    var resize = size.CalculateResize(wantedSize.GetMaxSize());
    var quality = wantedSize.GetQuality();

    using (var output = ImageProcessHelper.Process(streams[index], resize, quality))
    {
        var path = await AzureBlobHelper.SaveFileAsync(output, FileType.Image);
        var result = await _db.AddImageAsync(id, wantedSize, imageNumber, path);
        return result;
    }
  });

  await Task.WhenAll(tasks)

  if (!tasks.All(task => task.Result))
      return new ApiResponse(ResponseStatus.Fail);

非常感谢任何帮助!

【问题讨论】:

  • 您似乎同时在多个线程中使用_db,是否允许多个线程同时调用_db.AddImageAsync? (这根本与您的问题无关,但这是我看到很多人使用异步时犯的常见错误)
  • 好点,@ScottChamberlain - 我怀疑不是。我喜欢很多在我被赶上之前 - 它没有向数据库添加任何东西!出于兴趣,您知道当您尝试使用这样的非线程安全方法时,幕后究竟发生了什么吗?
  • 不支持对多个并发请求使用 DbContext(即使请求都在同一个线程上进行)并且具有未定义的行为,因此您将收到 Nasal Demons(又名:任何事情都可能发生,它可以工作,它可能会引发错误,它可能看起来像是在工作,但是将损坏的数据放入您的数据库中,它可能会使守护进程飞出您的鼻子)

标签: c# asp.net .net async-await


【解决方案1】:

因为.Select( 是惰性求值并返回IEnumerable<Task<bool>>,所以当您多次迭代结果时,会导致.Select( 运行多次。在其上抛出.ToList() 使其成为List<Task<bool>>,并且只会执行一次.Select(,并且多个枚举将超过返回的List<Task<bool>>,不会产生副作用。

  var tasks = wantedSizes.Select(async (wantedSize, index) =>
  {
    var resize = size.CalculateResize(wantedSize.GetMaxSize());
    var quality = wantedSize.GetQuality();

    using (var output = ImageProcessHelper.Process(streams[index], resize, quality))
    {
        var path = await AzureBlobHelper.SaveFileAsync(output, FileType.Image);
        //Double check your documentation, is _db.AddImageAsync thread safe?
        var result = await _db.AddImageAsync(id, wantedSize, imageNumber, path);
        return result;
    }
  }).ToList(); //We run the Select once here to process the .ToList().

  await Task.WhenAll(tasks) //This is the first enumeration of the variable "tasks".

  if (!tasks.All(task => task.Result)) //This is a 2nd enumeration of the variable.
      return new ApiResponse(ResponseStatus.Fail);

【讨论】:

  • +1,并澄清一下:一切都返回 false 的原因是 AddImageAsync 可能在第二次使用相同 ID 调用它时返回 false,因为图像没有任何改变第二次。
猜你喜欢
  • 2015-10-06
  • 2021-09-09
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
  • 1970-01-01
相关资源
最近更新 更多