Cada vez que necesite 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 ejemplo, pero lo mismo se aplica a Find()yFindAsync() .
Supongamos que tiene una lista myListde más de 100 elementos 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 crea una instancia de MyEDM, agrega la lista myLista la tabla MyTable, luego llamaSaveChanges() para persistir los cambios en la base de datos. Funciona como lo desea, los registros se confirman, pero su programa no puede hacer nada más hasta que finalice la confirmación. Esto puede llevar mucho tiempo dependiendo de lo que esté cometiendo. Si está realizando 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 hilo para manejar el inserto. Si bien esto liberará el hilo de llamada para continuar ejecutándose, creó un nuevo hilo que simplemente se quedará allí y esperará. No hay necesidad de esa sobrecarga, y esto es lo async awaitque resuelve el patrón.
Para operaciones de E / S, awaitse convierte rápidamente en su 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, crea una instancia de MyEDMy agrega sumyList a MyTable. ¡Pero cuando llamas await context.SaveChangesAsync(), la ejecución del código vuelve a la función que llama! Entonces, mientras espera que todos esos registros se confirmen, 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<MyTable> saveList), 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");
}
Por qué tendrías una función como esta, no lo sé, pero lo que genera muestra cómo async awaitfunciona. Primero repasemos lo que sucede.
La ejecución ingresa MyCallingFunction, Function Startingluego Save Startingse escribe en la consola y luego SaveChangesAsync()se llama a la función . En este punto, la ejecución regresa MyCallingFunctione ingresa al bucle for escribiendo 'Continuar con la ejecución' hasta 1000 veces. CuandoSaveChangesAsync() finaliza, la ejecución vuelve a la SaveRecordsfunción, escribiendo Save Completeen la consola. Una vez que todo esté SaveRecordscompleto, la ejecución continuará en el lugar MyCallingFunctioncorrecto donde estaba cuando SaveChangesAsync()terminó. ¿Confuso? Aquí hay una salida de ejemplo:
Función de inicio
Guardar comenzando
¡Continuando ejecutando!
¡Continuando ejecutando!
¡Continuando ejecutando!
¡Continuando ejecutando!
¡Continuando ejecutando!
....
¡Continuando ejecutando!
¡Guardar completo!
¡Continuando ejecutando!
¡Continuando ejecutando!
¡Continuando ejecutando!
....
¡Continuando ejecutando!
¡Función completada!
O tal vez:
Función de inicio
Guardar comenzando
¡Continuando ejecutando!
¡Continuando ejecutando!
¡Guardar completo!
¡Continuando ejecutando!
¡Continuando ejecutando!
¡Continuando ejecutando!
....
¡Continuando ejecutando!
¡Función completada!
Esa es la belleza de async awaitsu código puede continuar ejecutándose mientras espera que algo termine. En realidad, tendrías una función más como esta como tu función de llamada:
public async Task MyCallingFunction()
{
List<Task> myTasks = new List<Task>();
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 de guardar registros al mismo tiempo . MyCallingFunctionse completará mucho más rápido usando async awaitque si las SaveRecordsfunciones individuales fueran llamadas en serie.
Lo único que aún no he mencionado es la awaitpalabra clave. Lo que hace esto es detener la ejecución de la función actual hasta Taskque se complete lo que está esperando. Entonces, en el caso del original MyCallingFunction, la línea Function Completeno se escribirá en la consola hasta SaveRecordsque finalice la función.
En pocas palabras, si tiene una opción para usar async await, debería hacerlo, ya que aumentará en gran medida el rendimiento de su aplicación.