¿Cuál es la diferencia entre .Wait () vs .GetAwaiter (). GetResult ()?

88

Mi método regresa Task. Quiero esperar hasta que termine. ¿Qué debo usar .Wait()o .GetAwaiter().GetResult()? ¿Cuál es la diferencia entre ellos?


fuente

Respuestas:

107

Ambos son una espera sincrónica del resultado de la operación (y debe evitarlos si es posible).

La diferencia está principalmente en el manejo de excepciones. Con Wait, el seguimiento de la pila de excepciones no se modifica y representa la pila real en el momento de la excepción, por lo que si tiene un fragmento de código que se ejecuta en un subproceso de grupo de subprocesos, tendría una pila como

ThreadPoolThread.RunTask
YourCode.SomeWork

Por otro lado, .GetAwaiter().GetResult()reelaborará el seguimiento de la pila para tener en cuenta todo el contexto asincrónico, ignorando que algunas partes del código se ejecutan en el subproceso de la interfaz de usuario y otras en un subproceso de ThreadPool, y algunas son simplemente E / S asincrónicas. Por lo tanto, el seguimiento de la pila reflejará un paso sincrónico en su código :

TheSyncMethodThatWaitsForTheAsyncMethod
YourCode.SomeAsyncMethod
SomeAsync
YourCode.SomeWork

Esto tiende a hacer que los seguimientos de la pila de excepciones sean mucho más útiles, por decir lo menos. Puede ver dónde YourCode.SomeWorkse llamó en el contexto de su aplicación , en lugar de "la forma física en que se ejecutó".

Un ejemplo de cómo funciona esto está en la fuente de referencia (no contractual, por supuesto).

Luaan
fuente
6
Task.GetAwaiter () devuelve un TaskAwaiter . Sin embargo, el documento de TaskAwaiter.GetResult () advierte: "Esta API es compatible con la infraestructura del producto y no está diseñada para usarse directamente desde su código". ¿Puedes comentar?
DavidRR
23
@DavidRR El conjunto TaskAwaiteres un detalle de implementación. Por otro lado, el mecanismo de espera / espera está documentado y utiliza el tipo de pato: GetAwaiteres awaitcomo GetEnumeratorestá foreacho Disposeestá using. Todo esto se define en la especificación de C # independientemente del tipo de espera que se utilice; tenga en cuenta que Task.GetAwaiterestá "destinado al uso del compilador en lugar de al código de la aplicación". Pero el punto es que el uso previsto es hacer un await, no Wait()ni GetAwaiter().GetResult(), pero GetResultle brinda mejores pilas si lo necesita.
Luaan