Quelle est la différence entre .Wait () et .GetAwaiter (). GetResult ()?

88

Ma méthode revient Task. Je veux attendre la fin. Que dois-je utiliser .Wait()ou .GetAwaiter().GetResult()? Quelle est la différence entre eux?


la source

Réponses:

107

Les deux sont une attente synchrone du résultat de l'opération (et vous devez les éviter si possible).

La différence réside principalement dans la gestion des exceptions. Avec Wait, la trace de pile d'exceptions n'est pas modifiée et représente la pile réelle au moment de l'exception, donc si vous avez un morceau de code qui s'exécute sur un thread de pool de threads, vous auriez une pile comme

ThreadPoolThread.RunTask
YourCode.SomeWork

D'autre part, .GetAwaiter().GetResult()retravaillera la trace de la pile pour prendre en compte tout le contexte asynchrone, en ignorant que certaines parties du code s'exécutent sur le thread d'interface utilisateur, et d'autres sur un thread ThreadPool, et certaines sont simplement des E / S asynchrones. Ainsi, votre trace de pile reflétera une étape synchrone dans votre code :

TheSyncMethodThatWaitsForTheAsyncMethod
YourCode.SomeAsyncMethod
SomeAsync
YourCode.SomeWork

Cela a tendance à rendre les traces de pile d'exceptions beaucoup plus utiles, c'est le moins qu'on puisse dire. Vous pouvez voir où a YourCode.SomeWorkété appelé dans le contexte de votre application , plutôt que "la manière physique dont elle a été exécutée".

Un exemple de la façon dont cela fonctionne est dans la source de référence (non contractuelle, bien sûr).

Luaan
la source
6
Task.GetAwaiter () renvoie un TaskAwaiter . Cependant, la documentation de TaskAwaiter.GetResult () conseille: "Cette API prend en charge l'infrastructure du produit et n'est pas destinée à être utilisée directement à partir de votre code." Pouvez-vous commenter?
DavidRR
23
@DavidRR L'ensemble TaskAwaiterest un détail d'implémentation. D'autre part, le mécanisme awaitable / de awaiter est documenté, et les utilisations de canard frappe - GetAwaiterest awaitcomme GetEnumeratorc'est foreachou Disposeest de using. Tout cela est défini dans la spécification C # quel que soit le serveur particulier utilisé - notez qu'il Task.GetAwaiterest "destiné à être utilisé par le compilateur plutôt qu'à être utilisé dans le code d'application". Mais le fait est que l'utilisation prévue est de faire un await, pas Wait()ni GetAwaiter().GetResult()- mais GetResultvous donne de plus belles piles si vous en avez besoin.
Luaan