В чем разница между .Wait () и .GetAwaiter (). GetResult ()?

88

Мой метод возвращается Task. Я хочу подождать, пока он не закончится. Что мне использовать .Wait()или .GetAwaiter().GetResult()? В чем разница между ними?


источник

Ответы:

107

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

Разница в основном заключается в обработке исключений. С Wait, трассировка стека исключений не изменяется и представляет фактический стек во время исключения, поэтому, если у вас есть фрагмент кода, который выполняется в потоке пула потоков, у вас будет стек вида

ThreadPoolThread.RunTask
YourCode.SomeWork

С другой стороны, .GetAwaiter().GetResult()будет переработана трассировка стека, чтобы учесть весь асинхронный контекст, игнорируя, что некоторые части кода выполняются в потоке пользовательского интерфейса, а некоторые - в потоке ThreadPool, а некоторые представляют собой просто асинхронный ввод-вывод. Таким образом, ваша трассировка стека будет отражать синхронный шаг по вашему коду :

TheSyncMethodThatWaitsForTheAsyncMethod
YourCode.SomeAsyncMethod
SomeAsync
YourCode.SomeWork

Это, мягко говоря, делает трассировку стека исключений намного более полезной. Вы можете видеть, где YourCode.SomeWorkбыл вызван в контексте вашего приложения , а не «физический способ его запуска».

Пример того, как это работает, можно найти в справочном источнике (разумеется, вне договора).

Луаан
источник
6
Task.GetAwaiter () возвращает TaskAwaiter . Однако в документе для TaskAwaiter.GetResult () говорится: «Этот API поддерживает инфраструктуру продукта и не предназначен для использования непосредственно из вашего кода». Вы можете прокомментировать?
DavidRR
23
@DavidRR В целом TaskAwaiterэто деталь реализации. С другой стороны, механизм awaitable / awaiter документирован, и использует утиную типизацию - GetAwaiterэто , awaitкак GetEnumeratorэто foreachили Disposeэто using. Все это определено в спецификации C # независимо от конкретного используемого средства ожидания - обратите внимание, что Task.GetAwaiterоно «предназначено для использования компилятором, а не для использования в коде приложения». Но дело в том, что предполагаемое использование состоит в том, чтобы делать await, а не Wait()или GetAwaiter().GetResult()- но GetResultдает вам более красивые стеки, если вам это нужно.
Луаан