.net - promises - ¿Mi comprensión de async/await, cómo funciona y sus beneficios, es correcto?
como funciona async await javascript (1)
Eso es bastante correcto.
Algunas notas sin embargo:
- El hilo que comienza a ejecutar un método asíncrono es el hilo de la persona que llama, que puede o no ser un hilo de
ThreadPool
. - Si se alcanza una espera, pero la espera (generalmente, la
Task
) ya se completó, el hilo continuará ejecutando el resto del método de forma síncrona. - El hilo que reanuda la ejecución del método generalmente es un hilo
ThreadPool
, pero eso depende deSyncrhonizationContext
yTaskScheduler
. - El JIT no está involucrado aquí (no más de lo habitual). El compilador es el que convierte un método asíncrono en la máquina de estados. Puedes ver eso con este ejemplo de TryRoslyn .
- Es cierto que async-await no implica necesariamente concurrencia, ya que podría ser un solo hilo. Sin embargo, aún puede ser concurrente incluso con un solo hilo al iniciar y esperar múltiples operaciones asíncronas al mismo tiempo.
- async-await y el TPL no son partes completamente separadas. async-await está construido sobre la TPL. Es por eso que se llama el patrón asíncrono basado en tareas.
- Si bien la mayoría de las operaciones verdaderamente asíncronas son E / S, no todas lo son. También suele retrasar de forma asíncrona con
Task.Delay
o usar construcciones de sincronización asíncronas comoSemaphoreSlim.WaitAsync
.
He afirmado mi comprensión de async / await en un par de ocasiones, a menudo con algún debate sobre si estoy en lo correcto o no. Realmente apreciaría si alguien pudiera confirmar o negar mi comprensión, y aclarar cualquier idea errónea para que no difundiera información errónea.
Comprensión de alto nivel
async
/ await
es una forma de evitar el infierno de devolución de llamada al escribir código asíncrono. Un subproceso que está ejecutando un método asíncrono volverá al grupo de subprocesos cuando encuentre una await
y retomará la ejecución una vez que se complete la operación esperada.
Comprensión de bajo nivel
El JIT dividirá los métodos asíncronos en partes discretas alrededor de los puntos de await
, lo que permitirá volver a ingresar al método con el estado del método preservado. Bajo las cubiertas esto implica algún tipo de máquina de estados.
Relación con la concurrencia
async
/ await
no implica ningún tipo de concurrencia. Una aplicación escrita usando async
/ await
podría ser completamente de un solo hilo y aún así obtener todos los beneficios, de la misma manera que node.js lo hace con devoluciones de llamada. A diferencia de node.js, .NET es multiproceso, por lo que al tener async
/ await
, obtiene los beneficios de no bloquear la E / S sin usar devoluciones de llamada y al mismo tiempo tener varios subprocesos de ejecución.
Los beneficios
async
/ await
libera hilos para hacer otras cosas mientras espera que se complete IO. También se puede utilizar junto con el TPL para realizar trabajos vinculados a la CPU en varios subprocesos o fuera del subproceso de la interfaz de usuario.
Para beneficiarse de la IO sin bloqueo, los métodos asíncronos deben construirse sobre API que realmente aprovechan la IO sin bloqueo que finalmente proporciona el SO.
Mal uso
Este es el punto de discusión más grande en mi entendimiento. Mucha gente cree que envolver una operación de bloqueo en una Task
y usar async
/ await
provocará un aumento del rendimiento. Al crear un subproceso adicional para manejar una operación, devolver el subproceso original al grupo de subprocesos y luego reanudar el método original una vez finalizada la tarea, todo lo que está ocurriendo son cambios de contexto innecesarios, mientras que en realidad no libera los subprocesos para realizar otro trabajo. Si bien esto no es un mal uso de async
/ await
como lo es la TPL, esta mentalidad parece provenir de un malentendido de async
/ await
.