【问题标题】:Catching exceptions in Task.WhenAll在 Task.WhenAll 中捕获异常
【发布时间】:2020-05-16 02:09:52
【问题描述】:

一个类有异步方法MonitorAsync(),它启动一个长时间运行的并行操作。我收集了这些monitors;这些都是这样开始的:

    internal async Task RunAsync()
    {
        var tasks = monitors.Select((p) => p.Value.MonitorAsync());
        await Task.WhenAll(tasks);
    }

如果monitor 倒下,我需要知道(基本上我会再次运行它)。我已经查看了ContinueWith 等等,但是当并行运行一堆异步任务时,我如何确保我明确知道一个任务何时结束?

就上下文而言,RunAsync 基本上是我的应用程序的核心。

【问题讨论】:

标签: c# .net task-parallel-library


【解决方案1】:

如果显示器摔倒了,我需要知道(基本上我会再次运行它)。

最简单的方法是在一个单独的方法中定义这个逻辑:

internal async Task RunAsync()
{
  var tasks = monitors.Select(p => MonitorAndRestart(p));
  await Task.WhenAll(tasks);

  async Task MonitorAndRestart(P p)
  {
    while (true)
    {
      try { await p.Value.MonitorAsync(); }
      catch { ... }
      p.Restart();
    }
  }
}

【讨论】:

    【解决方案2】:

    如果您想知道一个何时结束(并且这不会影响其他人),ContinueWith() 可能是一种方式。

    或者,WaitAny 在循环中怎么样?

    while(anyTaskUnfinished){
        await Task.WaitAny(tasks);
    }
    //Stuff you do after WhenAll() comes here
    

    我不确定您是否必须删除已完成的任务。或者,如果它等待任何新的完成。

    【讨论】:

      【解决方案3】:

      你可以试试这个:

      如果不想调用 Task.Wait 方法等待任务完成,也可以从任务的 Exception 属性中检索 AggregateException 异常

      internal async Task RunAsync()
      {
          var tasks = monitors.Select((p) => p.Value.MonitorAsync());
          try
          {
              await Task.WhenAll(tasks);
          }
          catch (Exception)
          {
              foreach (var task in tasks.Where(x => x.IsFaulted))
              foreach (var exception in task.Exception.InnerExceptions)
              {
                  // Do Something
              }
          }
      }
      

      参考:Exception handling (Task Parallel Library)

      【讨论】:

      • 此解决方案将延迟重启失败的监视器,直到所有其他监视器都完成。这可能为时已晚。
      猜你喜欢
      • 1970-01-01
      • 2020-11-04
      • 1970-01-01
      • 2010-10-03
      • 2012-07-10
      • 1970-01-01
      • 2011-05-29
      • 2011-07-02
      • 2021-08-19
      相关资源
      最近更新 更多