【问题标题】:Task.WhenAny and Unobserved ExceptionsTask.WhenAny 和未观察到的异常
【发布时间】:2012-09-22 13:57:54
【问题描述】:

假设我有三个任务,abc。这三个都保证在 1 到 5 秒之间的随机时间抛出异常。然后我编写以下代码:

await Task.WhenAny(a, b, c);

这最终会从首先出错的任务中抛出异常。因为这里没有try...catch,所以这个异常会冒泡到我的代码中的其他地方。

当剩下的两个任务抛出异常时会发生什么?这些未观察到的异常,不就是会导致整个进程被杀死吗?这是否意味着使用WhenAny 的唯一方法是在try...catch 块内,然后在继续之前以某种方式观察剩余的两个任务?

跟进:我希望答案适用于带有异步目标包的 .NET 4.5 .NET 4.0(尽管显然使用 TaskEx.WhenAny在那种情况下)。

【问题讨论】:

  • 你尝试运行代码看看会发生什么吗?
  • @Servy 终结器没有抛出,但我看不出一个很好的理由。
  • 我想你的意思是Task.WhenAny()await Task.WaitAny() 甚至不会编译。
  • 这里有个错误的前提:Task.WhenAnyTask.WaitAny 永远不会抛出异常。
  • @DavidPfeffer 我不这么认为。等待从WhenAny 返回的任务不会抛出。它返回导致 WhenAny 运行完成的任务,等待 that 任务将抛出。

标签: c# .net task-parallel-library .net-4.5 async-await


【解决方案1】:

当剩下的两个任务抛出异常时会发生什么?

那些Tasks 将在故障状态下完成。

这些未观察到的异常,不就是会导致整个进程被杀死吗?

没有了。

在 .NET 4.0 中,Task 析构函数会将其未观察到的异常传递给 TaskScheduler.UnobservedTaskException,如果未处理,它将终止进程。

在 .NET 4.5 中,此 behavior was changed。现在,未观察到的异常被传递给TaskScheduler.UnobservedTaskException,但如果未处理,它们将被忽略。

【讨论】:

  • 在 .NET 4.0 上,这也不会终止终结器中的进程,我不知道为什么。
  • 如果您安装了 .NET 4.5,即使您的目标是 .NET 4.0,您也可以在 .NET 4.5 上运行。
  • 那么示例代码在 .NET 4.0 上真的失败了吗?有什么方法可以在我的 (4.5) 开发计算机上重现该行为?
  • 相信 Async Targeting Pack 实际上会添加一个UnobservedTaskException 处理程序来防止进程终止(我没有对此进行测试,但这是Async CTP 的行为.NET 4.0),所以任何使用 WhenAny 的东西都会表现相同。 an app config setting 让 .NET 4.5 模拟旧的 .NET 4.0 行为。
  • @KFL: await Task.WaitAny(..) 让您完成第一个任务;要观察该任务,您可以使用第二个 await:await await Task.WhenAny(..)
【解决方案2】:

是的,未观察到剩余的任务异常。在 .NET 4.5 之前,您有义务观察它们(不确定 .NET 4.5 的情况如何,但它发生了变化)。

我通常为自己编写一个辅助方法来处理这些即发即弃的任务:

    public static void IgnoreUnobservedExceptions(this Task task)
    {
        if (task.IsCompleted)
        {
            if (task.IsFaulted)
            {
                var dummy = task.Exception;
            }
            return;
        }

        task.ContinueWith(t =>
            {
                var dummy = t.Exception;
            }, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
    }

您可能希望在生产应用程序中包含日志记录。

【讨论】:

  • 在 .NET 4.0 上,这也不会终止终结器中的进程,我不知道为什么。
猜你喜欢
  • 2016-11-25
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
相关资源
最近更新 更多