Para un aprendizaje más rápido ...
Comprender el flujo de ejecución del método (con un diagrama): 3 minutos
Pregunta introspección (aprendizaje): 1 min.
Pasar rápidamente la sintaxis de azúcar: 5 minutos
Comparta la confusión de un desarrollador: 5 minutos
Problema: cambie rápidamente una implementación real del código normal a código asíncrono: 2 minutos
¿A dónde seguir?
Comprender el flujo de ejecución del método (con un diagrama): 3 minutos
En esta imagen, solo concéntrate en el n. ° 6 (nada más)
En el paso n. ° 6: la ejecución se detuvo aquí porque se ha quedado sin trabajo. Para continuar necesita un resultado de getStringTask (una especie de función). Por lo tanto, utiliza un await
operador para suspender su progreso y devolver el control (rendimiento) a la persona que llama (de este método en el que estamos). La llamada real a getStringTask se realizó anteriormente en el n. ° 2. En el n. ° 2 se hizo una promesa de devolver un resultado de cadena. ¿Pero cuándo devolverá el resultado? ¿Deberíamos (# 1: AccessTheWebAsync) hacer una segunda llamada nuevamente? Quién obtiene el resultado, # 2 (declaración de llamada) o # 6 (declaración de espera)
El llamador externo de AccessTheWebAsync () también está esperando ahora. Entonces, la persona que llama esperando AccessTheWebAsync, y AccessTheWebAsync está esperando GetStringAsync en este momento. Lo interesante es que AccessTheWebAsync trabajó un poco antes de esperar (# 4) quizás para ahorrar tiempo de espera. ¡La misma libertad para realizar múltiples tareas también está disponible para la persona que llama externa (y para todas las personas que llaman en la cadena) y esta es la mayor ventaja de esta cosa 'asincrónica'! Sientes que es sincrónico ... o normal, pero no lo es.
Recuerde, el método ya fue devuelto (# 2), no puede regresar nuevamente (sin segunda vez). Entonces, ¿cómo sabrá la persona que llama? ¡Se trata de tareas! La tarea fue aprobada. Se esperaba la tarea (sin método, sin valor). El valor se establecerá en la tarea. El estado de la tarea se configurará para completar. La persona que llama solo monitorea la Tarea (# 6). Entonces 6 # es la respuesta a dónde / quién obtiene el resultado. Más lecturas para más tarde aquí .
Pregunta introspección para aprender bien: 1 min
Ajustemos un poco la pregunta:
¿Cómo y cuándo usar y ? async
await
Tasks
Porque el aprendizaje Task
cubre automáticamente los otros dos (y responde a su pregunta)
Pasar rápidamente la sintaxis de azúcar: 5 minutos
Antes de la conversión (método original)
internal static int Method(int arg0, int arg1)
{
int result = arg0 + arg1;
IO(); // Do some long running IO.
return result;
}
un método de tarea para llamar al método anterior
internal static Task<int> MethodTask(int arg0, int arg1)
{
Task<int> task = new Task<int>(() => Method(arg0, arg1));
task.Start(); // Hot task (started task) should always be returned.
return task;
}
¿Mencionamos esperar o asíncrono? No. Llame al método anterior y obtendrá una tarea que puede monitorear. Ya sabes lo que devuelve la tarea ... un número entero.
Llamar a una tarea es un poco complicado y es cuando las palabras clave comienzan a aparecer. Llamemos MethodTask ()
internal static async Task<int> MethodAsync(int arg0, int arg1)
{
int result = await HelperMethods.MethodTask(arg0, arg1);
return result;
}
Mismo código de arriba agregado como imagen de abajo:
- Estamos 'esperando' la tarea para terminar. Por lo tanto, la
await
- Como usamos await, debemos usar
async
(sintaxis obligatoria)
- MethodAsync con
Async
como prefijo (estándar de codificación)
await
es fácil de entender pero los dos restantes ( async
, Async
) pueden no ser :). Así, se debe hacer mucho más sentido para el compilador lee though.Further para más adelante aquí
Entonces hay 2 partes.
- Crear 'tarea'
- Crear azúcar sintáctico para llamar a la tarea (
await+async
)
Recuerde, teníamos una llamada externa para AccessTheWebAsync () y esa llamada tampoco se salvó ... es decir, también necesita lo mismo await+async
. Y la cadena continúa. Pero siempre habrá un Task
en un extremo.
Todo está bien, pero un desarrollador se sorprendió al ver que faltaba el # 1 (Tarea) ...
Comparta la confusión de un desarrollador: 5 minutos
Un desarrollador ha cometido un error al no implementar, ¡ Task
pero aún funciona! Intente comprender la pregunta y solo la respuesta aceptada que se proporciona aquí . Espero que hayas leído y entendido completamente. El resumen es que es posible que no veamos / implementemos 'Tarea' pero se implementa en algún lugar de una clase principal. Del mismo modo, en nuestro ejemplo, llamar a un ya construido MethodAsync()
es mucho más fácil que implementar ese método con un Task
( MethodTask()
) nosotros mismos. A la mayoría de los desarrolladores les resulta difícil entender Tasks
cómo convertir un código a uno asíncrono.
Consejo: intente encontrar una implementación Async existente (como MethodAsync
o ToListAsync
) para externalizar la dificultad. Por lo tanto, solo tenemos que lidiar con Async y esperar (que es fácil y bastante similar al código normal)
Problema: cambie rápidamente una implementación del mundo real de código normal a operación asíncrona: 2 minutos
La línea de código que se muestra a continuación en la Capa de datos comenzó a romperse (en muchos lugares). Porque actualizamos parte de nuestro código de .Net framework 4.2. * A .Net core. ¡Tuvimos que arreglar esto en 1 hora en toda la aplicación!
var myContract = query.Where(c => c.ContractID == _contractID).First();
¡pan comido!
- Instalamos el paquete Nuget de EntityFramework porque tiene QueryableExtensions. O en otras palabras, no la ejecución asíncrono (tarea), por lo que podría sobrevivir con una simple
Async
y await
de código.
- espacio de nombres = Microsoft.EntityFrameworkCore
la línea del código de llamada se cambió así
var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
La firma del método cambió de
Contract GetContract(int contractnumber)
a
async Task<Contract> GetContractAsync(int contractnumber)
el método de llamada también se vio afectado: GetContractAsync(123456);
fue llamado comoGetContractAsync(123456).Result;
¡Lo cambiamos por todas partes en 30 minutos!
¡Pero el arquitecto nos dijo que no usáramos la biblioteca EntityFramework solo para esto! ¡Uy! ¡drama! Luego hicimos una implementación de Tarea personalizada (yuk). Que ya sabes cómo. Sigue siendo fácil! .. todavía yuk ..
¿A dónde seguir?
Hay un maravilloso video rápido que podríamos ver sobre la conversión de llamadas síncronas a asíncronas en ASP.Net Core , quizás esa sea la dirección que tomaría después de leer esto.