Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Você pode evitar gargalos de desempenho e aprimorar a capacidade de resposta geral do aplicativo usando programação assíncrona. No entanto, as técnicas tradicionais para desenvolver aplicativos assíncronos podem ser complicadas, dificultando seu desenvolvimento, depuração e manutenção.
O C# dá suporte à abordagem simplificada, programação assíncrona, que aproveita o suporte assíncrono no runtime do .NET. O compilador faz o trabalho difícil que o desenvolvedor costumava fazer e seu aplicativo mantém uma estrutura lógica semelhante a um código síncrono. Como resultado, você obtém todas as vantagens da programação assíncrona com uma fração do esforço.
Este tópico fornece uma visão geral de quando e como usar programação assíncrona e inclui links para tópicos de suporte que contêm detalhes e exemplos.
Async melhora a capacidade de resposta
A assincronia é essencial para atividades que são potencialmente bloqueantes, como o acesso à Web. Às vezes, o acesso a um recurso da Web é lento ou atrasado. Se essa atividade for bloqueada em um processo síncrono, todo o aplicativo deverá aguardar. Em um processo assíncrono, o aplicativo pode continuar com outro trabalho que não depende do recurso da Web até que a tarefa potencialmente bloqueada seja concluída.
A tabela a seguir mostra áreas típicas em que a programação assíncrona melhora a capacidade de resposta. As APIs listadas do .NET e do Windows Runtime contêm métodos que dão suporte à programação assíncrona.
Área do aplicativo | Tipos .NET com métodos assíncronos | Tipos do Windows Runtime com métodos assíncronos |
---|---|---|
Acesso à Web | HttpClient | Windows.Web.Http.HttpClient SyndicationClient |
Trabalhando com arquivos | JsonSerializer StreamReader StreamWriter XmlReader XmlWriter |
StorageFile |
Trabalhando com imagens | MediaCapture BitmapEncoder BitmapDecoder |
|
Programação do WCF | Operações síncronas e assíncronas |
A assincronia é especialmente importante para aplicativos que acessam o thread de interface de usuário porque todas as atividades relacionadas à interface do usuário normalmente compartilham um único thread. Se qualquer processo for bloqueado em um aplicativo síncrono, todos serão bloqueados. Seu aplicativo para de responder e você pode concluir que ele falhou quando estiver apenas aguardando.
Quando você usa métodos assíncronos, o aplicativo continua respondendo à interface do usuário. Você pode redimensionar ou minimizar uma janela, por exemplo, ou fechar o aplicativo se não quiser esperar que ela seja concluída.
A abordagem baseada em assíncrona adiciona o equivalente a uma transmissão automática à lista de opções que você pode escolher ao projetar operações assíncronas. Ou seja, você obtém todos os benefícios da programação assíncrona tradicional, mas com muito menos esforço do desenvolvedor.
Métodos assíncronos são fáceis de escrever
As palavras-chave assíncronas e await em C# são o coração da programação assíncrona. Usando essas duas palavras-chave, você pode usar recursos no .NET Framework, no .NET Core ou no Windows Runtime para criar um método assíncrono quase tão facilmente quanto criar um método síncrono. Métodos assíncronos que você define usando a async
palavra-chave são chamados de métodos assíncronos.
O exemplo a seguir mostra um método assíncrono. Quase tudo no código deve parecer familiar para você.
Você pode encontrar um exemplo completo do Windows Presentation Foundation (WPF) disponível para download em Programação Assíncrona com async e await em C#.
public async Task<int> GetUrlContentLengthAsync()
{
using var client = new HttpClient();
Task<string> getStringTask =
client.GetStringAsync("https://learn.microsoft.com/dotnet");
DoIndependentWork();
string contents = await getStringTask;
return contents.Length;
}
void DoIndependentWork()
{
Console.WriteLine("Working...");
}
Você pode aprender várias práticas com base no exemplo anterior. Comece com a assinatura do método. Ele inclui o async
modificador. O tipo de retorno é Task<int>
(consulte a seção "Tipos de Retorno" para obter mais opções). O nome do método termina em Async
. No corpo do método, GetStringAsync
retorna um Task<string>
. Isso significa que, quando você executar await
em uma tarefa, obterá uma string
(contents
). Antes de aguardar a tarefa, você poderá fazer um trabalho que não dependa da string
em GetStringAsync
.
Preste muita atenção no operador await
. Ele suspende GetUrlContentLengthAsync
:
-
GetUrlContentLengthAsync
não pode continuar até quegetStringTask
seja concluído. - Enquanto isso, o controle é retornado ao chamador de
GetUrlContentLengthAsync
. - O controle será retomado aqui quando a
getStringTask
for concluída. -
await
O operador então recupera ostring
resultado degetStringTask
.
A instrução return especifica um resultado inteiro. Os métodos que estão aguardando GetUrlContentLengthAsync
recuperar o valor de comprimento.
Se GetUrlContentLengthAsync
não tiver nenhum trabalho que possa fazer entre chamar GetStringAsync
e aguardar sua conclusão, você poderá simplificar seu código chamando e aguardando na instrução única a seguir.
string contents = await client.GetStringAsync("https://learn.microsoft.com/dotnet");
As seguintes características resumem o que torna o exemplo anterior um método assíncrono:
A assinatura do método inclui um
async
modificador.O nome de um método assíncrono, por convenção, termina com um sufixo "Assíncrono".
O tipo de retorno é um dos seguintes tipos:
-
Task<TResult> se o método tiver uma instrução return na qual o operando tem o tipo
TResult
. - Task se o método não tiver nenhuma instrução de retorno ou tiver uma instrução de retorno sem operando.
-
void
se você estiver escrevendo um manipulador de eventos assíncrono. - Qualquer outro tipo que tenha um método
GetAwaiter
.
Para obter mais informações, consulte a seção Tipos de retorno e parâmetros .
-
Task<TResult> se o método tiver uma instrução return na qual o operando tem o tipo
O método geralmente inclui pelo menos uma
await
expressão, que marca um ponto em que o método não pode continuar até que a operação assíncrona aguardada seja concluída. Enquanto isso, o método é suspenso e o controle retorna ao chamador do método. A próxima seção deste tópico ilustra o que acontece no ponto de suspensão.
Em métodos assíncronos, você usa as palavras-chave e os tipos fornecidos para indicar o que deseja fazer e o compilador faz o restante, incluindo manter o controle do que deve acontecer quando o controle retorna a um ponto de espera em um método suspenso. Alguns processos rotineiros, como loops e tratamento de exceções, podem ser difíceis de lidar no código assíncrono tradicional. Em um método assíncrono, você escreve esses elementos da mesma forma que faria em uma solução síncrona e o problema é resolvido.
Para obter mais informações sobre assíncrona em versões anteriores do .NET Framework, consulte TPL e programação assíncrona tradicional do .NET Framework.
O que acontece em um método assíncrono
O mais importante a entender na programação assíncrona é como o fluxo de controle se move de método para método. O diagrama a seguir leva você ao processo:
Os números no diagrama correspondem às etapas a seguir, iniciadas quando um método de chamada chama o método assíncrono.
Um método de chamada chama e aguarda o método assíncrono
GetUrlContentLengthAsync
.GetUrlContentLengthAsync
cria uma HttpClient instância e chama o GetStringAsync método assíncrono para baixar o conteúdo de um site como uma cadeia de caracteres.Algo acontece em
GetStringAsync
que suspende seu progresso. Talvez ele deva aguardar o download de um site ou alguma outra atividade causadora de bloqueio. Para evitar o bloqueio de recursos,GetStringAsync
gera controle ao chamador.GetUrlContentLengthAsync
GetStringAsync
retorna um Task<TResult>, ondeTResult
é uma cadeia de caracteres eGetUrlContentLengthAsync
atribui a tarefa àgetStringTask
variável. A tarefa representa o processo contínuo para a chamada aGetStringAsync
, com um compromisso de produzir um valor de cadeia de caracteres real quando o trabalho estiver concluído.Como
getStringTask
ainda não foi aguardado,GetUrlContentLengthAsync
pode continuar com outros trabalhos que não dependem do resultado final deGetStringAsync
. Esse trabalho é representado por uma chamada para o métodoDoIndependentWork
síncrono.DoIndependentWork
é um método síncrono que faz seu trabalho e retorna ao chamador.GetUrlContentLengthAsync
está sem trabalho que ele possa executar sem um resultado degetStringTask
.GetUrlContentLengthAsync
Em seguida, deseja calcular e retornar o comprimento da cadeia de caracteres baixada, mas o método não pode calcular esse valor até que o método tenha a cadeia de caracteres.Portanto,
GetUrlContentLengthAsync
usa um operador await para suspender seu progresso e gerar controle ao método chamadoGetUrlContentLengthAsync
.GetUrlContentLengthAsync
retorna umTask<int>
para o chamador. A tarefa representa uma promessa de produzir um resultado inteiro que é o comprimento da cadeia de caracteres baixada.Observação
Se
GetStringAsync
(e, portanto,getStringTask
) for concluído antes queGetUrlContentLengthAsync
o aguarde, o controle permanecerá emGetUrlContentLengthAsync
. A despesa de suspender e depois voltar aGetUrlContentLengthAsync
seria desperdiçada se o processo assíncronogetStringTask
chamado já tiver sido concluído eGetUrlContentLengthAsync
não precisar aguardar o resultado final.Dentro do método de chamada, o padrão de processamento continua. O chamador pode realizar outro trabalho que não dependa do resultado de
GetUrlContentLengthAsync
antes de aguardar esse resultado, ou o chamador pode aguardar imediatamente. O método de chamada está aguardandoGetUrlContentLengthAsync
eGetUrlContentLengthAsync
está aguardandoGetStringAsync
.GetStringAsync
completa e produz um resultado de cadeia de caracteres. O resultado da cadeia de caracteres não é retornado pela chamadaGetStringAsync
da maneira que você pode esperar. (Lembre-se de que o método já retornou uma tarefa na etapa 3.) Em vez disso, o resultado da cadeia de caracteres é armazenado na tarefa que representa a conclusão do método.getStringTask
O operador await recupera o resultado degetStringTask
. A instrução de atribuição atribui o resultado recuperado acontents
.Quando
GetUrlContentLengthAsync
tem o resultado da cadeia de caracteres, o método pode calcular o comprimento da cadeia de caracteres. Em seguida, o trabalho deGetUrlContentLengthAsync
também é concluído e o manipulador de eventos de espera poderá retomar. No exemplo completo no final do tópico, é possível confirmar que o manipulador de eventos recuperou e imprimiu o valor do comprimento do resultado. Se você não estiver familiarizado com a programação assíncrona, leve um minuto para considerar a diferença entre o comportamento síncrono e assíncrono. Um método síncrono retorna quando seu trabalho é concluído (etapa 5), mas um método assíncrono retorna um valor de tarefa quando seu trabalho é suspenso (etapas 3 e 6). Quando o método assíncrono eventualmente conclui seu trabalho, a tarefa é marcada como concluída e o resultado, se houver, é armazenado na tarefa.
Métodos assíncronos da API
Você pode estar se perguntando onde encontrar métodos como GetStringAsync
que dão suporte à programação assíncrona. O .NET Framework 4.5 ou superior e o .NET Core contêm muitos membros que trabalham com async
e await
. Você pode reconhecê-los pelo sufixo "Assíncrono" acrescentado ao nome do membro e pelo tipo de retorno de Task ou Task<TResult>. Por exemplo, a System.IO.Stream
classe contém métodos como CopyToAsync, ReadAsynce WriteAsync ao lado dos métodos CopyTosíncronos, Reade Write.
O Windows Runtime também contém muitos métodos que você pode usar com async
e await
em aplicativos do Windows. Para obter mais informações, veja Threading e programação assíncrona para o desenvolvimento da UWP e Programação assíncrona (aplicativos da Windows Store) e Início Rápido: chamando APIs assíncronas em C# ou Visual Basic se você usa versões anteriores do Windows Runtime.
Fios
Os métodos assíncronos destinam-se a operações sem bloqueio. Uma await
expressão em um método assíncrono não bloqueia o thread atual enquanto a tarefa aguardada está em execução. Em vez disso, a expressão inscreve o restante do método como uma continuação e retorna o controle ao chamador do método assíncrono.
As palavras-chave async
e await
não fazem com que threads adicionais sejam criadas. Os métodos assíncronos não exigem multithreading porque um método assíncrono não é executado em seu próprio thread. O método é executado no contexto de sincronização atual e usa o tempo no thread somente quando o método está ativo. Você pode usar Task.Run para mover o trabalho associado à CPU para um thread em segundo plano, mas um thread em segundo plano não ajuda com um processo que está apenas aguardando que os resultados fiquem disponíveis.
A abordagem baseada em async para programação assíncrona é preferível às abordagens existentes em quase todos os casos. Essa abordagem é especialmente mais eficiente do que a classe BackgroundWorker para operações de entrada e saída, porque o código é mais simples e você não precisa se proteger contra condições de corrida. Em combinação com o método Task.Run, a programação assíncrona é melhor do que BackgroundWorker para operações associadas à CPU, pois a programação assíncrona separa os detalhes de coordenação da execução do código do trabalho que Task.Run
transfere para o pool de threads.
async e await
Se você especificar que um método é um método assíncrono usando o modificador assíncrono , habilite os dois recursos a seguir.
O método assíncrono marcado pode usar await para designar pontos de suspensão. O
await
operador informa ao compilador que o método assíncrono não pode continuar além desse ponto até que o processo assíncrono aguardado seja concluído. Enquanto isso, o controle retorna para o chamador do método assíncrono.A suspensão de um método assíncrono em uma
await
expressão não constitui uma saída do método efinally
os blocos não são executados.O método assíncrono marcado pode ele próprio ser aguardado por métodos que o chamam.
Um método assíncrono normalmente contém uma ou mais ocorrências de um await
operador, mas a ausência de await
expressões não causa um erro do compilador. Se um método assíncrono não usar um await
operador para marcar um ponto de suspensão, o método será executado como um método síncrono, apesar do async
modificador. O compilador emite um aviso para esses métodos.
async
e await
são palavras-chave contextuais. Para obter mais informações e exemplos, consulte os seguintes tópicos:
- assíncrono
- esperar
Tipos e parâmetros de retorno
Um método assíncrono normalmente retorna um Task ou um Task<TResult>. Dentro de um método assíncrono, um await
operador é aplicado a uma tarefa retornada de uma chamada para outro método assíncrono.
Especifique Task<TResult> como o tipo de retorno se o método contiver uma return
instrução que especifica um operando do tipo TResult
.
Você usará Task como o tipo de retorno se o método não tiver nenhuma instrução de retorno ou tiver uma instrução de retorno que não retorne um operando.
Você também pode especificar qualquer outro tipo de retorno, desde que o tipo inclua um GetAwaiter
método.
ValueTask<TResult> é um exemplo desse tipo. Ele está disponível no pacote NuGet System.Threading.Tasks.Extension .
O exemplo a seguir mostra como você declara e chama um método que retorna um Task<TResult> ou um Task:
async Task<int> GetTaskOfTResultAsync()
{
int hours = 0;
await Task.Delay(0);
return hours;
}
Task<int> returnedTaskTResult = GetTaskOfTResultAsync();
int intResult = await returnedTaskTResult;
// Single line
// int intResult = await GetTaskOfTResultAsync();
async Task GetTaskAsync()
{
await Task.Delay(0);
// No return statement needed
}
Task returnedTask = GetTaskAsync();
await returnedTask;
// Single line
await GetTaskAsync();
Cada tarefa retornada representa o trabalho em andamento. Uma tarefa encapsula informações sobre o estado do processo assíncrono e, eventualmente, o resultado final do processo ou a exceção que o processo gera se não for bem-sucedido.
Um método assíncrono também pode ter um void
tipo de retorno. Esse tipo de retorno é usado principalmente para definir manipuladores de eventos, em que um void
tipo de retorno é necessário. Manipuladores de eventos assíncronos geralmente servem como ponto de partida para programas assíncronos.
Um método assíncrono que tem o tipo de retorno void
não pode ser esperado, e o chamador de um método que retorna nulo não pode capturar nenhuma exceção lançada pelo método.
Um método assíncrono não pode declarar parâmetros de entrada, ref ou saída , mas o método pode chamar métodos que têm esses parâmetros. Da mesma forma, um método assíncrono não pode retornar um valor por referência, embora possa chamar métodos que retornam valores por referência.
Para obter mais informações e exemplos, consulte tipos de retorno assíncronos (C#).
As APIs assíncronas na programação do Windows Runtime têm um dos seguintes tipos de retorno, semelhantes a tarefas:
- IAsyncOperation<TResult>, que corresponde a Task<TResult>
- IAsyncAction, que corresponde a Task
- IAsyncActionWithProgress<TProgress>
- IAsyncOperationWithProgress<TResult,TProgress>
Convenção de nomenclatura
Por convenção, os métodos que retornam tipos normalmente aguardados (por exemplo, Task
, , Task<T>
ValueTask
, ) ValueTask<T>
devem ter nomes que terminam com "Async". Os métodos que iniciam uma operação assíncrona, mas não retornam um tipo aguardável não devem ter nomes que terminam com "Async", mas podem começar com "Begin", "Start" ou algum outro verbo que indique que esse método não retorna nem gera o resultado da operação.
Você pode ignorar a convenção em que um evento, uma classe base ou um contrato de interface sugere um nome diferente. Por exemplo, você não deve renomear manipuladores de eventos comuns, como OnButtonClick
.
Artigos relacionados (Visual Studio)
Título | Descrição |
---|---|
Como fazer várias solicitações da Web em paralelo usando assíncrono e await (C#) | Demonstra como iniciar várias tarefas ao mesmo tempo. |
Tipos de retorno assíncronos (C#) | Ilustra os tipos que os métodos assíncronos podem retornar e explica quando cada tipo é apropriado. |
Cancelar tarefas usando um token de cancelamento como mecanismo de sinalização. | Mostra como adicionar a seguinte funcionalidade à sua solução assíncrona: - Cancelar uma lista de tarefas (C#) - Cancelar tarefas após um período de tempo (C#) - Processar tarefas assíncronas conforme elas forem concluídas (C#) |
Usando assíncrono para acesso a arquivos (C#) | Lista e demonstra os benefícios de usar assíncrono e aguardar para acessar arquivos. |
Padrão assíncrono baseado em tarefa (TAP) | Descreve um padrão assíncrono, o padrão é baseado nos tipos Task e Task<TResult>. |
Vídeos assíncronos no Canal 9 | Fornece links para uma variedade de vídeos sobre programação assíncrona. |
Consulte também
- Programação assíncrona com async e await
- assíncrono
- esperar