Programação Assíncrona em C#: guia completo na prática
Programação assíncrona é um dos conceitos-chave do desenvolvimento moderno em C# e na plataforma .NET. Ela permite criar aplicações responsivas que não bloqueiam o fluxo de execução ao aguardar operações longas: leitura de arquivos, consultas a banco de dados, chamadas HTTP. Neste guia, vamos explorar como a assincronicidade funciona em C#, com exemplos práticos usando as palavras-chave async e await, além de abordar as melhores práticas.
O que é programação assíncrona e por que ela é necessária?
Na programação síncrona, cada operação é executada sequencialmente. Se um método chama, por exemplo, o download de dados da rede, o fluxo de execução é bloqueado até que a operação seja concluída. Isso causa "congelamento" da interface em aplicações desktop ou uso ineficiente dos recursos do servidor em aplicações web.
A programação assíncrona resolve esse problema: o fluxo não é bloqueado, mas retorna ao pool de threads para processar outras tarefas. Quando a operação é concluída, a execução é retomada de onde foi interrompida.
Principais vantagens da assincronicidade em C#:
- Responsividade da UI — a aplicação não congela durante operações longas.
- Escalabilidade de servidores — uma única thread pode atender muitas requisições.
- Uso eficiente de recursos — menos tempo ocioso de threads.
Fundamentos de async e await em C#
As palavras-chave async e await são açúcar sintático que simplifica o trabalho com operações assíncronas. Vejamos um exemplo básico:
using System;using System.Net.Http;using System.Threading.Tasks;
public class AsyncExample{ public async Task<string> DownloadDataAsync(string url) { using (var client = new HttpClient()) { // await não bloqueia a thread string result = await client.GetStringAsync(url); return result; } }
public async Task RunAsync() { Console.WriteLine("Iniciando download..."); string data = await DownloadDataAsync("https://api.example.com/data"); Console.WriteLine($"Baixado: {data.Length} caracteres"); }}Explicação do código:
- O método é marcado com
async— isso permite o uso deawaitinternamente. - O tipo de retorno é
Task<string>(ou apenasTaskpara métodos void). awaitpausa a execução do método até obter o resultado, mas não bloqueia a thread.
Importante: O método Main em uma aplicação de console C# 7.1+ também pode ser assíncrono:
static async Task Main(string[] args){ var example = new AsyncExample(); await example.RunAsync();}Trabalhando com Task e Task<T>
O tipo Task representa uma operação assíncrona. Ele pode estar nos estados: pendente (Pending), em execução (Running), concluído (Completed), com erro (Faulted) ou cancelado (Canceled).
Vejamos como criar e iniciar tarefas manualmente:
public async Task ProcessDataAsync(){ // Criamos uma tarefa que é executada no pool de threads Task<int> task = Task.Run(() => { // Simulação de trabalho longo Task.Delay(2000).Wait(); return 42; });
// Aguardamos o resultado int result = await task; Console.WriteLine($"Resultado: {result}");}Para execução paralela de várias tarefas, use Task.WhenAll:
public async Task DownloadMultipleAsync(){ var urls = new[] { "https://site1.com", "https://site2.com", "https://site3.com" }; var tasks =