Task.WhenAny和Unobserved Exceptions

Dav*_*fer 19 .net c# task-parallel-library async-await .net-4.5

比方说,我有三个任务,a,b,和c.所有这三个都保证在1到5秒之间的随机时间抛出异常.然后我写下面的代码:

await Task.WhenAny(a, b, c);
Run Code Online (Sandbox Code Playgroud)

这最终将从任何一个任务故障中抛出异常.由于这里没有try...catch,这个例外会冒泡到我的代码中的其他地方.

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

后续:我希望将答案同时应用于.NET 4.5 .NET 4.0以及Async Targeting Pack(尽管TaskEx.WhenAny在这种情况下明确使用).

Ste*_*ary 23

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

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

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

不再.

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

在.NET 4.5中,此行为已更改.现在,将未观察到的异常传递给TaskScheduler.UnobservedTaskException,但如果未处理则忽略它们.

  • 如果您安装了 .NET 4.5,即使您的目标是 .NET 4.0,您也会在 .NET 4.5 上运行。 (2认同)
  • 我*相信*Async Targeting Pack实际上会添加一个`UnobservedTaskException`处理程序来防止进程终止(我没有测试过这个,但这是.NET 4.0的Async CTP的行为),所以任何使用`WhenAny`的行为都会相同.有[应用程序配置设置](http://blogs.msdn.com/b/pfxteam/archive/2011/09/28/10217876.aspx)使.NET 4.5模拟旧的.NET 4.0行为. (2认同)
  • @KFL:`await Task.WaitAny(..)`使您完成第一个任务;要观察该任务,可以使用第二个await:`await await Task.WhenAny(..)` (2认同)

usr*_*usr 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);
    }
Run Code Online (Sandbox Code Playgroud)

您可能要在生产应用程序中包括日志记录。