Async e Await em C#: salvando a aplicação de "congelamentos"
\n\nVocê já executou um programa em C#, clicou em um botão e a interface "congelou" por alguns segundos? Ou, talvez, seu servidor parou de responder a novas requisições enquanto processava uma requisição "pesada"? Familiar? Este é o problema clássico do código síncrono, onde o fluxo de execução é bloqueado enquanto aguarda a conclusão de uma operação (leitura de arquivo, consulta ao banco de dados, chamada HTTP).
\n\nA solução para este problema é a programação assíncrona. E em C#, as principais ferramentas para isso são as palavras-chave async e await. Se você já se perguntou: "Como e quando usar async e await?" — você veio ao lugar certo. Neste tutorial, abordaremos tudo, desde o básico até as melhores práticas, para que você escreva código rápido, responsivo e escalável.
Este material é baseado em uma pergunta popular real do Stack Overflow, que reuniu milhares de visualizações. Nós o adaptamos para conteúdo educacional, adicionando exemplos de código e explicações claras.
\n\nO que são async e await? Em palavras simples
\n\nImagine que você é um chef de cozinha (seu programa). Você precisa preparar o jantar. Um dos pratos é uma sopa que deve cozinhar por 30 minutos. No mundo síncrono, você ficaria parado ao lado do fogão apenas esperando a sopa cozinhar, sem fazer nada. Bobo, não é?
\n\nAssincronia é quando você coloca a sopa para cozinhar (async) e, sem esperar, começa a cortar a salada, arrumar a mesa e cuidar de outras tarefas. Quando a sopa estiver pronta, você volta para ela (await). Você não perde tempo — você é eficiente.
- \n
async— um modificador de método que diz ao compilador: "Este método contém operações assíncronas. Não bloqueie a thread quando eu encontrarawait". \n await— um operador aplicado a uma tarefa (Task). Ele diz: "Pause a execução deste método até que a tarefa seja concluída, mas não bloqueie a thread. Assim que a tarefa for concluída, continue a execução a partir deste ponto". \n
Importante: await não bloqueia a thread. Ele retorna o controle ao código chamador, e a thread continua executando outro trabalho.
Quando usar async e await?
\n\nEsta é a pergunta mais frequente. A resposta é simples: sempre que você estiver executando uma operação que pode levar muito tempo (operações I/O-bound) e não quiser bloquear a thread.
\n\nAqui estão cenários típicos:
\n- \n
- Requisições de rede: Chamadas HTTP (HttpClient), trabalho com WebSocket. \n
- Trabalho com arquivos: Leitura/escrita de arquivos grandes, trabalho com streams. \n
- Consultas a bancos de dados: Entity Framework, ADO.NET, Dapper. \n
- Trabalho com serviços web: WCF, REST API. \n
- Qualquer operação de entrada/saída (I/O): Acesso a disco, rede, impressora. \n
Quando NÃO usar async e await?
\n- \n
- Operações CPU-bound: Se sua tarefa requer processamento intensivo (renderização 3D, processamento de vídeo, cálculos matemáticos complexos),
async/awaitnão ajudará. Aqui, useTask.RunouParallelpara paralelizar em vários núcleos da CPU. \n - Em construtores de classes: Construtores não podem ser async. Use métodos de fábrica (
public static async Task<MyClass> CreateAsync()). \n - Em getters/setters de propriedades: Eles também não podem ser async. Use métodos. \n
Como funciona? Análise com exemplo de código
\n\nVamos ver um código real. Imagine que estamos carregando dados de um servidor remoto.
\n\nExemplo ruim (síncrono)
\npublic string GetDataFromWeb()\n{\n usi