Task.WhenAny和Unobserved Exceptions

时间:2012-10-01 17:25:00

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

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

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

这最终将从任何一个任务故障中抛出异常。由于此处没有try...catch,因此此异常会冒泡到我的代码中的其他位置。

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

后续行动:我希望将答案同时应用于.NET 4.5 .NET 4.0以及Async Targeting Pack(尽管明确使用{{1在那种情况下)。

2 个答案:

答案 0 :(得分:23)

  

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

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

  

这些未被观察到的异常是否会导致整个过程被杀死?

不再。

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

在.NET 4.5中,这是behavior was changed。现在,未观察到的异常传递给TaskScheduler.UnobservedTaskException,但如果未处理则会被忽略。

答案 1 :(得分:5)

是的,未观察到剩余的任务异常。在.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);
    }

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