asincrona - async await c# ejemplos
¿Por qué C#permite realizar una anulación asincrónica? (3)
Cuando la clase base (o interfaz) declara un método virtual que devuelve una tarea, puede anularlo siempre que devuelva la tarea. La palabra clave async
es solo una sugerencia para que el compilador transforme su método en una máquina de estado. Aunque el compilador hace magia negra en su método, el método compilado todavía devuelve una Tarea .
En cuanto a los métodos virtuales void
, puede anular uno sin la palabra clave async
(obviamente) e iniciar una tarea no esperada dentro de ella. Eso es algo de lo que sucede cuando se anula con la palabra clave async
y se usa await
en el cuerpo. La persona que llama no esperaría la Tarea creada (ya que la firma "original" es void
). Ambos casos son similares *:
public override void MyVirtualMethod()
{
// Will create a non awaited Task (explicitly)
Task.Factory.StartNew(()=> SomeTaskMethod());
}
public override async void MyVirtualMethod()
{
// Will create a non awaited Task (the caller cannot await void)
await SomeTaskMethod();
}
El artículo de Stephen Cleary tiene algunas notas al respecto:
- Los métodos asíncronos que devuelven el vacío tienen un propósito específico: hacer posibles los controladores asíncronos de eventos.
- Debe preferir la tarea asíncrona a la anulación asíncrona.
* La implementación de SomeTaskMethod
, el marco subyacente, SynchronizationContext y otros factores puede y causará resultados diferentes para cada uno de los métodos anteriores.
En C #, cuando reemplaza un método, está permitido hacer que el reemplazo sea asíncrono cuando el método original no lo era. Esto parece ser una mala forma.
El problema que me hace preguntarme es el siguiente: me trajeron para ayudar con un problema de prueba de carga. En alrededor de 500 usuarios simultáneos, el proceso de inicio de sesión se dividiría en un bucle de redirección. IIS estaba registrando excepciones con el mensaje "Se completó un módulo o controlador asíncrono mientras aún estaba pendiente una operación asíncrona". Algunas búsquedas me llevaron a pensar que alguien estaba abusando de async void
, pero mis búsquedas rápidas a través de la fuente no encontraron nada.
Lamentablemente, estaba buscando async/s*void
(búsqueda de expresiones regulares) cuando debería haber estado buscando algo más parecido a async/s*[^T]
(suponiendo que la tarea no estaba completamente calificada ... entiendes el punto).
Lo que más tarde encontré fue una async override void onActionExecuting
en async override void onActionExecuting
de async override void onActionExecuting
en un controlador base. Claramente ese tenía que ser el problema, y así fue. Arreglar eso (haciéndolo sincrónico por el momento) resolvió el problema.
Pero me dejó con una pregunta: ¿Por qué puede marcar una anulación como asincrónica cuando el código de llamada nunca podría esperarla?
Puede anular el método async
porque asíncrono no forma parte de la firma del método. En realidad, async permite usar la palabra clave await
en su método mediante la creación de una máquina de estados en el interior.
Puede encontrar más información sobre async aquí: http://blog.sublogic.com/2012/05/14/async-isnt-really-part-of-your-method-signature/
async
no es parte del "contrato". Es un detalle de implementación que, en mi opinión, desafortunadamente, aparece en el lugar equivocado.
Es perfectamente legal cambiar un método (no async
) convirtiendo una Task
en una async
(o viceversa) sin que sea un cambio importante, y sin requerir que los llamadores compilen.
Otra indicación de que no forma parte del contrato es que no se le permite marcar funciones como async
dentro de las interfaces y, como aquí, es perfectamente posible anular async
con no async
o viceversa.