На собеседовании спросили что будет в данной ситуации если оба Task выбросят исключение и как в данном случае их нужно обрабатывать?
Task task1 = Method1Async();
Task task2 = Method2Async();
await task1;
await task2;
Ответ
Сперва немного теории. Как известно, async/await представляет по сути лишь синтаксический сахар, за кулисами же компилятор разворачивает асинхронный код в чуть более сложный. Что происходит, когда в методе, помеченном модификатором async, возникает исключение? Оно не выбрасывается тотчас наверх по стеку (потому что к тому моменту мы уже можем быть в совершенно другом месте), а помещается внутрь таска (см. свойство Exception). Сам метод при этом завершается нормально. Исключение же (оригинальное или обернутое в AggregateException) будет выброшено в нескольких случаях:
Кто-то ожидает таск (с помощью await или метода Wait()).
Кто-то обращается к результату (свойство Result, применимо только для Task
Исходя из этого, ответ на вопрос несколько "ветвист":
Вариант 1. Код работает под .NET младше 4.5, либо включена настройка ThrowUnobservedTaskExceptions
В таком случае исключение для первого таска будет выброшено, исключение второго таска останется unobserved. Если где-то выше по стэку исключение от первого таска было обработано, и приложение продолжило работу, то рано оно поздно оно упадет -- когда финализатор второго таска выбросит исключение.
Вариант 2. Код работает под .NET 4.5 и выше и настройка ThrowUnobservedTaskExceptions выключена.
В таком случае исключение для первого таска по-прежнему будет выброшено, исключение второго таска останется unobserved (увидеть его можно будет только подписавшись на событие TaskScheduler.UnobservedTaskException), но процесс не упадет.
Вариантов обработки исключения несколько:
Обернуть каждый await в отдельный блок try/catch. Плюс этого варианта в том, что вы получите и обработаете оба исключения.
Использовать await Task.WhenAll(task1, task2). Минус этого варианта в том, что вы получите информацию только о первом исключении.
Использовать Task.WaitAll(task1, task2). Плюс этого варианта в том, что вы получите AggregateException, который будет содержать в себе оба исключения. Минус этого варианта в том, что он блокирует текущий поток.
Комментариев нет:
Отправить комментарий