Jaka jest różnica między .Wait () a .GetAwaiter (). GetResult ()?

88

Moja metoda powraca Task. Chcę poczekać, aż to się skończy. Czego powinienem użyć .Wait()lub .GetAwaiter().GetResult()? Jaka jest różnica między nimi?


źródło

Odpowiedzi:

107

Oba są synchronicznym oczekiwaniem na wynik operacji (i należy ich unikać, jeśli to możliwe).

Różnica polega głównie na obsłudze wyjątków. W Waitprzypadku ślad stosu wyjątków jest niezmieniony i reprezentuje rzeczywisty stos w momencie wystąpienia wyjątku, więc jeśli masz fragment kodu działający w wątku puli wątków, masz stos taki jak

ThreadPoolThread.RunTask
YourCode.SomeWork

Z drugiej strony, .GetAwaiter().GetResult()zmieni ślad stosu, aby uwzględnić cały kontekst asynchroniczny, ignorując, że niektóre części kodu są wykonywane w wątku interfejsu użytkownika, a niektóre w wątku puli wątków, a niektóre są po prostu asynchronicznymi we / wy. Więc twój ślad stosu będzie odzwierciedlał synchroniczny krok w kodzie :

TheSyncMethodThatWaitsForTheAsyncMethod
YourCode.SomeAsyncMethod
SomeAsync
YourCode.SomeWork

To sprawia, że ​​ślady stosu wyjątków są co najmniej bardziej przydatne. Możesz zobaczyć, gdzie YourCode.SomeWorkzostało wywołane w kontekście Twojej aplikacji , a nie „fizyczny sposób, w jaki została uruchomiona”.

Przykład tego, jak to działa, znajduje się w źródle referencyjnym (oczywiście poza umową).

Luaan
źródło
6
Task.GetAwaiter () zwraca TaskAwaiter . Jednak dokumentacja TaskAwaiter.GetResult () zawiera zalecenie: „Ten interfejs API obsługuje infrastrukturę produktu i nie jest przeznaczony do użytku bezpośrednio z Twojego kodu”. Czy możesz skomentować?
DavidRR
23
@DavidRR Całość TaskAwaiterto szczegół implementacji. Z drugiej strony, mechanizm awaitable / awaiter jest udokumentowany i wykorzystuje pisanie typu kaczego - GetAwaiterjest do tego, awaitco GetEnumeratorjest foreachlub Disposejest do using. Wszystko to jest zdefiniowane w specyfikacji C # niezależnie od używanego konkretnego awaitera - uwaga, że Task.GetAwaiterjest „przeznaczone raczej do użytku przez kompilator niż do użycia w kodzie aplikacji”. Ale chodzi o to, że zamierzonym zastosowaniem jest wykonanie an await, a nie Wait()norGetAwaiter().GetResult() - ale GetResultdaje ładniejsze stosy, jeśli tego potrzebujesz.
Luaan