Страницы

Поиск по вопросам

воскресенье, 1 декабря 2019 г.

Task.GetAwaiter().GetResult() или Task.Result

#c_sharp

Вопрос такой: Почему надо использовать один способ и почему нельзя использовать другой?

На MSDN пишут:


  Этот метод в первую очередь предназначен для использования компилятором, а не для
использования в коде приложения.


Но покопавшись в интернете нашёл, что Task.Result исключения оборачивает в AggregateException
- это вся разница о которой пишут.

Хотелось бы узнать эту тему глубже.
Если будет официальная литература в которой объясняется этот вопрос - буду только
рад увидеть её здесь!
    


Ответы

Ответ 1



Замечание, на которое вы ссылаетесь, рекомендует не работать с awaiter'ом напрямую, а использовать await. Конструкция await использует GetAwaiter «под капотом». Но она, в отличие от вашего кода, получает результат асинхронно. Синхронное получение асинхронного результата опасно, и если не на все 100% представляете себе все тонкости происходящего — вы на верном пути к deadlock'у. В качестве примера, давайте рассмотрим вот такой код: async Task GetOneAsync() { await Task.Delay(1000); return 1; } int one = GetOneAsync().GetAwaiter().GetResult(); Если вы выполните это в UI-потоке, возникнет deadlock. Видите, почему? Task, возвращаемый из GetOneAsync, ожидает окончания таймаута, после чего собирается вернуться в UI-поток, чтобы выполнить return 1;. Но GetResult() блокирует UI-поток до получения результата! Таким образом, в функции GetOneAsync возврат в UI-поток никогда не произойдёт. Прямой вызов GetResult() не приводит к проблемам в некоторых случаях — например, в случае, если Task уже завершён. Вот эту самую проверку компилятор делает, так что его вызов GetResult более безопасен. Резюмируя: прямая работа с awaiter'ом чревата ошибками. Поэтому рекомендуется не работать с awaiter'ом вручную, а использовать await. А использование Task.Result настолько же опасно, как и .GetAwaiter().GetResult(). Старайтесь не использовать ни первое, ни второе.

Комментариев нет:

Отправить комментарий