Недавно я читал код, в котором используется много асинхронных методов, но иногда их нужно выполнять синхронно. Код делает:
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: «Этот тип и его члены предназначены для использования компилятором». Другой человек не должен его использовать.