Es importante comprender el código correctamente antes de adaptarlo a tu trabajo si tquieres aportar algo puedes comentarlo.
Solución:
Cada vez que necesita realizar una acción en un servidor remoto, su programa genera la solicitud, la envía y luego espera una respuesta. usaré SaveChanges()
y SaveChangesAsync()
como un ejemplo, pero lo mismo se aplica a Find()
y FindAsync()
.
Di que tienes una lista myList
de más de 100 artículos que necesita agregar a su base de datos. Para insertar eso, su función se vería así:
using(var context = new MyEDM())
context.MyTable.AddRange(myList);
context.SaveChanges();
Primero creas una instancia de MyEDM
agrega la lista myList
a la mesa MyTable
luego llame SaveChanges()
para persistir los cambios en la base de datos. Funciona como usted quiere, los registros se confirman, pero su programa no puede hacer nada más hasta que finaliza la confirmación. Esto puede tomar mucho tiempo dependiendo de lo que estés cometiendo. Si está confirmando cambios en los registros, la entidad tiene que confirmarlos uno a la vez (¡una vez tuve que guardar 2 minutos para las actualizaciones)!
Para resolver este problema, puede hacer una de dos cosas. La primera es que puede iniciar un nuevo subproceso para manejar la inserción. Si bien esto liberará el subproceso de llamada para continuar ejecutándose, creó un nuevo subproceso que simplemente se quedará allí y esperará. No hay necesidad de esa sobrecarga, y esto es lo que el async await
patrón resuelve.
Para operaciones de E/S, await
rápidamente se convierte en tu mejor amigo. Tomando la sección de código de arriba, podemos modificarla para que sea:
using(var context = new MyEDM())
Console.WriteLine("Save Starting");
context.MyTable.AddRange(myList);
await context.SaveChangesAsync();
Console.WriteLine("Save Complete");
Es un cambio muy pequeño, pero tiene efectos profundos en la eficiencia y el rendimiento de su código. ¿Así que lo que pasa? El comienzo del código es el mismo, creas una instancia de MyEDM
y agrega tu myList
para MyTable
. Pero cuando llamas await context.SaveChangesAsync()
la ejecución del código vuelve a la función de llamada! Entonces, mientras espera que se confirmen todos esos registros, su código puede continuar ejecutándose. Digamos que la función que contenía el código anterior tenía la firma de public async Task SaveRecords(List
la función de llamada podría verse así:
public async Task MyCallingFunction()
Console.WriteLine("Function Starting");
Task saveTask = SaveRecords(GenerateNewRecords());
for(int i = 0; i < 1000; i++)
Console.WriteLine("Continuing to execute!");
await saveTask;
Console.Log("Function Complete");
No sé por qué tendría una función como esta, pero lo que genera muestra cómo async await
obras. Primero repasemos lo que sucede.
La ejecución entra MyCallingFunction
, Function Starting
luego Save Starting
se escribe en la consola, entonces la función SaveChangesAsync()
se llama En este punto, la ejecución vuelve a MyCallingFunction
e ingresa al bucle for escribiendo 'Continuing to Execute' hasta 1000 veces. Cuándo SaveChangesAsync()
termina, la ejecución vuelve a la SaveRecords
función, escritura Save Complete
a la consola Una vez todo dentro SaveRecords
completa, la ejecución continuará en MyCallingFunction
justo donde estaba cuando SaveChangesAsync()
finalizado. ¿Confundido? Aquí hay una salida de ejemplo:
Function Starting Save Starting Continuing to execute! Continuing to execute! Continuing to execute! Continuing to execute! Continuing to execute! .... Continuing to execute! Save Complete! Continuing to execute! Continuing to execute! Continuing to execute! .... Continuing to execute! Function Complete!
O tal vez:
Function Starting Save Starting Continuing to execute! Continuing to execute! Save Complete! Continuing to execute! Continuing to execute! Continuing to execute! .... Continuing to execute! Function Complete!
Esa es la belleza de async await
, su código puede continuar ejecutándose mientras espera que algo termine. En realidad, tendría una función más como esta como su función de llamada:
public async Task MyCallingFunction()
List myTasks = new List();
myTasks.Add(SaveRecords(GenerateNewRecords()));
myTasks.Add(SaveRecords2(GenerateNewRecords2()));
myTasks.Add(SaveRecords3(GenerateNewRecords3()));
myTasks.Add(SaveRecords4(GenerateNewRecords4()));
await Task.WhenAll(myTasks.ToArray());
Aquí tiene cuatro funciones diferentes para guardar registros. al mismo tiempo. MyCallingFunction
se completará mucho más rápido usando async await
que si el individuo SaveRecords
Las funciones se llamaban en serie.
Lo único que no he tocado todavía es el await
palabra clave. Lo que esto hace es detener la ejecución de la función actual hasta que lo que sea Task
usted está esperando completa. Así que en el caso del original MyCallingFunction
la línea Function Complete
no se escribirá en la consola hasta que el SaveRecords
termina la función.
Para resumir, si tiene una opción para usar async await
debería hacerlo, ya que aumentará en gran medida el rendimiento de su aplicación.
Recuerda que tienes el privilegio reseñar tu experiencia si te fue útil.