Недавно я читал код, в котором используется много асинхронных методов, но иногда их нужно выполнять синхронно. Код делает:
Foo foo = GetFooAsync(...).GetAwaiter().GetResult();
Это то же самое, что
Foo foo = GetFooAsync(...).Result;
Недавно я читал код, в котором используется много асинхронных методов, но иногда их нужно выполнять синхронно. Код делает:
Foo foo = GetFooAsync(...).GetAwaiter().GetResult();
Это то же самое, что
Foo foo = GetFooAsync(...).Result;
async
/ await
в MVC)
Ответы:
Довольно много. Однако есть одно небольшое отличие: в случае Task
сбоя GetResult()
будет просто сгенерировано исключение, вызванное напрямую, а Task.Result
сгенерируется файл AggregateException
. Однако какой смысл использовать любой из них, если он есть async
? В 100 раз лучший вариант - использовать await
.
Кроме того, вы не должны использовать GetResult()
. Он предназначен только для использования компилятором, а не для вас. Но если вы не хотите раздражать AggregateException
, используйте это.
async Task
модульные тесты и уже некоторое время поддерживают их .
The 100x better option is to use await.
Я ненавижу подобные заявления, если бы я мог дать им пощечину, я бы сделал await
это. Но, когда я пытаюсь получить асинхронный код для работы с не-асинхронным кодом , как то , что часто случается со мной много в Xamarin, я в конечном итоге того , чтобы использовать такие вещи , как ContinueWith
много для того , чтобы сделать это не тупиковую интерфейс. Изменить: я знаю, что это старый, но это не облегчает мое разочарование, когда я ищу ответы, в которых говорится об отсутствии альтернатив для ситуаций, когда вы не можете просто использовать await
.
Task.GetAwaiter().GetResult()
предпочтительнее, Task.Wait
и Task.Result
потому что он распространяет исключения, а не помещает их в файл AggregateException
. Однако все три метода могут привести к тупиковой ситуации и нехватке пула потоков. Их следует избегать в пользу async/await
.
Цитата ниже объясняет, почему, Task.Wait
а Task.Result
не просто содержит поведение распространения исключения Task.GetAwaiter().GetResult()
(из-за «очень высокой панели совместимости»).
Как я упоминал ранее, у нас очень высокая планка совместимости, и поэтому мы избежали критических изменений. Таким образом,
Task.Wait
сохраняет свое первоначальное поведение - всегда обертывание. Однако вы можете оказаться в некоторых сложных ситуациях, когда вам нужно поведение, подобное синхронной блокировке, используемойTask.Wait
, но где вы хотите, чтобы исходное исключение распространялось развернутым, а не заключалось вAggregateException
. Для этого вы можете напрямую настроить таргетинг на ожидающего задачи. Когда вы пишете «await task;
», компилятор переводит это в использованиеTask.GetAwaiter()
метода, который возвращает экземпляр, у которого естьGetResult()
метод. При использовании для неисправной ЗадачиGetResult()
будет распространяться исходное исключение (так «await task;
» получает свое поведение). Таким образом, вы можете использовать "task.GetAwaiter().GetResult()
”, Если вы хотите напрямую вызвать эту логику распространения.
https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/
«
GetResult
» Фактически означает «проверить задачу на наличие ошибок»В общем, я изо всех сил стараюсь избегать синхронной блокировки асинхронной задачи. Однако есть несколько ситуаций, когда я нарушаю это правило. В этих редких случаях я предпочитаю метод,
GetAwaiter().GetResult()
потому что он сохраняет исключения задач, а не помещает их в файлAggregateException
.
http://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html
Task.GetAwaiter().GetResult()
эквивалентно await task
. Я предполагаю, что первый вариант используется, когда метод не может быть помечен async
(например, конструктором). Это верно? Если да, то он совпадает с верхним ответом @ It'sNotALie
Task.GetAwaiter().GetResult()
более эквивалентен Task.Wait
и Task.Result
(в том смысле, что все три будут синхронно блокироваться и иметь потенциал для взаимоблокировок), но Task.GetAwaiter().GetResult()
имеет поведение распространения исключений задачи ожидания.
https://github.com/aspnet/Security/issues/59
"И последнее замечание: вам следует избегать использования
Task.Result
иTask.Wait
по возможности, поскольку они всегда инкапсулируют внутреннее исключение вAggregateException
и заменяют сообщение общим (произошла одна или несколько ошибок), что затрудняет отладку. Даже если синхронная версия не должна не будет использоваться так часто, вам следует серьезно подумать об использованииTask.GetAwaiter().GetResult()
вместо этого ".
Task.WhenAll(task1, task2).GetAwaiter().GetResult();
.
Другое отличие заключается в том, что async
функция возвращает только Task
вместо Task<T>
этого, вы не можете использовать
GetFooAsync(...).Result;
В то время как
GetFooAsync(...).GetAwaiter().GetResult();
еще работает.
Я знаю, что пример кода в вопросе предназначен для данного случая Task<T>
, однако вопрос задается в целом.
Result
с GetIntAsync()
которой возвращается Task<int>
не только Task
. Предлагаю вам еще раз прочитать мой ответ.
GetFooAsync(...).Result
внутри возвращающей функции Task
. Теперь это имеет смысл, поскольку в C # нет void Properties ( Task.Result
это свойство), но вы, конечно, можете вызвать метод void.
Как уже упоминалось, если вы можете использовать await
. Если вам нужно запускать код синхронно, как вы упомянули .GetAwaiter().GetResult()
, .Result
или .Wait()
существует риск возникновения взаимоблокировок, как многие сказали в комментариях / ответах. Поскольку большинству из нас нравятся одинарные лайнеры, вы можете использовать их для.Net 4.5<
Получение значения с помощью асинхронного метода:
var result = Task.Run(() => asyncGetValue()).Result;
Синхронный вызов асинхронного метода
Task.Run(() => asyncMethod()).Wait();
Проблемы с взаимоблокировкой не возникнут из-за использования Task.Run
.
Источник:
В случае сбоя задачи исключение создается повторно, когда код продолжения вызывает awaiter.GetResult (). Вместо вызова GetResult мы могли бы просто получить доступ к свойству Result задачи. Преимущество вызова GetResult заключается в том, что в случае сбоя задачи исключение выдается напрямую, без упаковки в AggregateException, что позволяет использовать более простые и чистые блоки catch.
Для неуниверсальных задач GetResult () возвращает недействительное значение. Его полезная функция состоит исключительно в том, чтобы повторно генерировать исключения.
источник: С # 7.0 в двух словах
GetResult
: «Этот тип и его члены предназначены для использования компилятором». Другой человек не должен его использовать.