Бросить исключение внутри задачи - "ожидание" против ожидания ()

static async void Main(string[] args)
{
    Task t = new Task(() => { throw new Exception(); });

    try
    {                
        t.Start();
        t.Wait();                
    }
    catch (AggregateException e)
    {
        // When waiting on the task, an AggregateException is thrown.
    }

    try
    {                
        t.Start();
        await t;
    }
    catch (Exception e)
    {
        // When awating on the task, the exception itself is thrown.  
        // in this case a regular Exception.
    }           
}

В TPL, при создании исключения внутри Задачи, оно оборачивается исключением AggregateException.
Но то же самое не происходит при использовании ключевого слова await.
Чем объясняется такое поведение?

2 ответа

Решение

Цель состоит в том, чтобы заставить его выглядеть / вести себя как синхронная версия. Джон Скит делает большую работу, объясняя это в своей серии Eduasync, особенно в этом посте:

http://codeblog.jonskeet.uk/2011/06/22/eduasync-part-11-more-sophisticated-but-lossy-exception-handling/

В TPL AggregateException используется потому, что в операции ожидания может быть несколько задач (к задаче могут быть прикреплены дочерние задачи), поэтому многие из них могут выдавать исключения. Посмотрите на исключения в разделе дочерних задач

https://msdn.microsoft.com/ru-ru/library/dd997417(v=vs.110).aspx

В await у вас всегда есть только одна задача

Смотрите также https://msdn.microsoft.com/ru-ru/library/dd997415(v=vs.110).aspx

Вот хорошее объяснение в деталях, Стивен Тауб, почему существует разница в типе исключений между Task.Wait() и await:

Обработка исключений задач в.NET 4.5

При разработке Task.Wait в.NET 4 мы выбрали всегда распространение агрегата. На это решение повлияла необходимость не перезаписывать детали, но также и основной вариант использования для задач в то время, как параллелизм форка / соединения, где вероятность множественных исключений довольно распространена.

Хотя и похож на Task.Wait на высоком уровне (т. Е. Продвижение вперед не выполняется до тех пор, пока задача не завершится), "await task" представляет собой совершенно другой основной набор сценариев. Вместо того, чтобы использоваться для параллелизма fork/join, наиболее распространенным использованием "задачи ожидания" является получение последовательного синхронного фрагмента кода и превращение его в последовательный асинхронный фрагмент кода. В тех местах кода, где вы выполняете синхронную операцию, вы заменяете ее асинхронной операцией, представленной задачей, и "ожидаете" ее. Таким образом, хотя вы, безусловно, можете использовать await для операций fork/join (например, с помощью Task.WhenAll), это не 80% случай. Кроме того, в.NET 4.5 представлено введение System.Runtime.ExceptionServices.ExceptionDispatchInfo, которое решает проблему, позволяющую распределять исключения между потоками без потери деталей исключений, таких как трассировка стека и сегменты Watson. Для данного объекта исключения вы передаете его в ExceptionDispatchInfo.Create, который возвращает объект ExceptionDispatchInfo, который содержит ссылку на объект Exception и копию его сведений. Когда приходит время выбросить исключение, метод Throw объекта ExceptionDispatchInfo используется для восстановления содержимого исключения и его выброса без потери исходной информации (информация о текущем стеке вызовов добавляется к тому, что уже сохранено в исключении).

Учитывая это, и снова имея выбор всегда бросать первое или всегда бросать совокупность, для "ожидания" мы предпочитаем всегда бросать первое. Это не значит, что у вас нет доступа к одним и тем же деталям. Во всех случаях свойство Exception задачи по-прежнему возвращает исключение AggregateException, содержащее все исключения, поэтому вы можете отследить любое выброшенное значение и вернуться, чтобы при необходимости обратиться к Task.Exception. Да, это приводит к несоответствию между поведением исключений при переключении между "task.Wait()" и "await task", но мы рассматривали это как существенное меньшее из двух зол.

Другие вопросы по тегам