Sempre que você precisar realizar uma ação em um servidor remoto, seu programa gera a solicitação, a envia e espera por uma resposta. Vou usar SaveChanges()e SaveChangesAsync()como exemplo, mas o mesmo se aplica a Find()e FindAsync().
Digamos que você tenha uma lista myListde mais de 100 itens que precise adicionar ao seu banco de dados. Para inserir isso, sua função seria mais ou menos assim:
using(var context = new MyEDM())
{
context.MyTable.AddRange(myList);
context.SaveChanges();
}
Primeiro você cria uma instância de MyEDM, adiciona a lista myListà tabela e MyTable, em seguida, chama SaveChanges()para persistir as alterações no banco de dados. Funciona como você deseja, os registros são confirmados, mas seu programa não pode fazer mais nada até que a confirmação seja concluída. Isso pode levar muito tempo, dependendo do que você está enviando. Se você está enviando alterações para os registros, a entidade tem que confirmá-las, uma de cada vez (uma vez, um salvamento levou 2 minutos para atualizações)!
Para resolver esse problema, você pode fazer uma das duas coisas. A primeira é que você pode iniciar uma nova rosca para lidar com a inserção. Embora isso libere o encadeamento de chamada para continuar em execução, você criou um novo encadeamento que vai ficar parado e esperar. Não há necessidade dessa sobrecarga, e é isso que o async awaitpadrão resolve.
Para operações de I / O, awaitrapidamente se torna seu melhor amigo. Pegando a seção de código acima, podemos modificá-la para ser:
using(var context = new MyEDM())
{
Console.WriteLine("Save Starting");
context.MyTable.AddRange(myList);
await context.SaveChangesAsync();
Console.WriteLine("Save Complete");
}
É uma mudança muito pequena, mas há efeitos profundos na eficiência e no desempenho do seu código. Então o que acontece? O início do código é o mesmo, você cria uma instância de MyEDMe adiciona seu myLista MyTable. Mas quando você chama await context.SaveChangesAsync(), a execução do código retorna para a função de chamada! Portanto, enquanto você espera a confirmação de todos esses registros, seu código pode continuar a ser executado. Digamos que a função que continha o código acima tivesse a assinatura de public async Task SaveRecords(List<MyTable> saveList), a função de chamada poderia ter a seguinte aparência:
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 que você teria uma função como esta, eu não sei, mas o que sai mostra como async awaitfunciona. Primeiro, vamos ver o que acontece.
Execução entra MyCallingFunction, Function Startingem seguida, Save Startingé escrita para o console, em seguida, a função SaveChangesAsync()é chamada. Neste ponto, a execução retorna MyCallingFunctione entra no loop for escrevendo 'Continuing to Execute' até 1000 vezes. Ao SaveChangesAsync()terminar, a execução retorna à SaveRecordsfunção, gravando Save Completeno console. Depois que tudo estiver SaveRecordsconcluído, a execução continuará da maneira MyCallingFunctioncorreta onde estava antes SaveChangesAsync(). Confuso? Aqui está um exemplo de saída:
Início da função
Salvar começando
Continuando a executar!
Continuando a executar!
Continuando a executar!
Continuando a executar!
Continuando a executar!
....
Continuando a executar!
Salvar concluído!
Continuando a executar!
Continuando a executar!
Continuando a executar!
....
Continuando a executar!
Função concluída!
Ou talvez:
Início da função
Salvar começando
Continuando a executar!
Continuando a executar!
Salvar concluído!
Continuando a executar!
Continuando a executar!
Continuando a executar!
....
Continuando a executar!
Função concluída!
Essa é a beleza de async await, seu código pode continuar a ser executado enquanto você espera que algo termine. Na realidade, você teria uma função mais parecida com esta como sua função de chamada:
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());
}
Aqui, você tem quatro funções diferentes de salvar gravação em execução ao mesmo tempo . MyCallingFunctionserá concluído muito mais rápido usando do async awaitque se as SaveRecordsfunções individuais fossem chamadas em série.
A única coisa que ainda não mencionei é a awaitpalavra - chave. O que isso faz é parar a execução da função atual até que tudo Tasko que você está esperando seja concluído. Portanto, no caso do original MyCallingFunction, a linha Function Completenão será gravada no console até que a SaveRecordsfunção seja concluída.
Resumindo, se você tem uma opção de usar async await, você deve, pois isso aumentará muito o desempenho do seu aplicativo.