Мій метод повертається Task
. Я хочу почекати, поки все закінчиться. Що я повинен використовувати
.Wait()
або .GetAwaiter().GetResult()
? Яка різниця між ними?
Мій метод повертається Task
. Я хочу почекати, поки все закінчиться. Що я повинен використовувати
.Wait()
або .GetAwaiter().GetResult()
? Яка різниця між ними?
Відповіді:
І те, і інше - це синхронне очікування результату операції (і вам слід уникати таких, якщо це можливо).
Різниця полягає головним чином у обробці винятків. З Wait
, трасування стека винятків є незмінним і представляє фактичний стек на момент виключення, тому, якщо у вас є фрагмент коду, який працює на потоці пулу потоків, у вас буде такий стек, як
ThreadPoolThread.RunTask
YourCode.SomeWork
З іншого боку, .GetAwaiter().GetResult()
буде перероблено трасування стека, щоб врахувати весь асинхронний контекст, ігноруючи, що деякі частини коду виконуються в потоці інтерфейсу користувача, а деякі - у потоці ThreadPool, а деякі - просто асинхронним введенням-виведенням. Отже, ваш стек трасування відображатиме синхронний крок вашого коду :
TheSyncMethodThatWaitsForTheAsyncMethod
YourCode.SomeAsyncMethod
SomeAsync
YourCode.SomeWork
Це, як правило, робить сліди стеків винятків набагато кориснішими, м’яко кажучи. Ви можете бачити, де YourCode.SomeWork
було викликано в контексті вашої програми , а не "фізичний спосіб її запуску".
Приклад того, як це працює, є в довідковому джерелі (звичайно, поза договірним договором).
TaskAwaiter
це є деталлю реалізації. З іншого боку, механізм очікуваного / очікуючого задокументований і використовує набір качок - GetAwaiter
це await
як GetEnumerator
є, foreach
чи Dispose
є using
. Все це визначено в специфікації C # незалежно від конкретного використовуваного очікувача - зауважте, що Task.GetAwaiter
"призначений для використання компілятором, а не для використання в коді програми". Але справа в тому, що передбачуване використання полягає у виконанні await
, а не Wait()
ні, GetAwaiter().GetResult()
- але GetResult
надає вам приємніші стеки, якщо вам це потрібно.