Introdução à programação assíncrona em C#
Programação assíncrona é um dos conceitos-chave do desenvolvimento moderno em C#. Na era de aplicações web de alta carga, microsserviços e soluções em nuvem, a capacidade de trabalhar eficientemente com assincronia tornou-se uma habilidade obrigatória para todo desenvolvedor .NET.
O objetivo principal da programação assíncrona é não bloquear o thread de execução durante a espera por operações longas (entrada/saída, trabalho com rede, consultas a banco de dados). Em vez disso, o thread é liberado para processar outras tarefas, o que aumenta significativamente a performance e escalabilidade da aplicação.
Neste artigo, abordaremos:
- Fundamentos de async/await em C#
- Trabalho com a classe Task
- Regras para escrever métodos assíncronos
- Erros típicos e como evitá-los
Fundamentos de async/await em C#
O paradigma central da programação assíncrona em C# é construído em duas palavras-chave: async e await. Elas foram introduzidas no C# 5.0 e desde então se tornaram o padrão para trabalhar com assincronia.
Como funciona async/await
A palavra-chave async é usada para declarar um método assíncrono. await é aplicado a uma tarefa (Task) para pausar a execução do método até sua conclusão, sem bloquear o thread atual.
public async Task<string> GetDataAsync(){ // Simulação de uma requisição HTTP assíncrona using var client = new HttpClient(); string result = await client.GetStringAsync("https://api.example.com/data"); return result;}
public async Task ProcessAsync(){ string data = await GetDataAsync(); Console.WriteLine($"Dados recebidos: {data}");}É importante entender: await não bloqueia o thread. Ele transfere o controle para o código chamador, e quando a tarefa é concluída, o método continua a execução do mesmo ponto.
Tipos de valores de retorno de métodos assíncronos
Um método assíncrono pode retornar um de três tipos:
Task— para métodos que não retornam valorTask<T>— para métodos que retornam um valor do tipo TValueTask<T>— para cenários de alta performance, quando o resultado está frequentemente disponível de forma síncrona
// Sem valor de retornopublic async Task SaveDataAsync(string data){ await File.WriteAllTextAsync("data.txt", data);}
// Com valor de retornopublic async Task<int> CalculateSumAsync(int a, int b){ await Task.Delay(100); // Simulação de operação longa return a + b;}
// ValueTask para otimizaçãopublic async ValueTask<bool> CheckCacheAsync(string key){ if (_cache.ContainsKey(key)) return true; await Task.Delay(50); return false;}Trabalho avançado com Task
A classe Task é a base da programação assíncrona em C#. Vamos examinar os métodos e padrões mais úteis.
Execução paralela de tarefas
Os métodos Task.WhenAll e Task.WhenAny permitem gerenciar eficientemente múltiplas operações assíncronas.
public async Task ProcessMultipleRequestsAsync(){ var task1 = FetchDataAsync("url1"); var task2 = FetchDataAsync("url2"); var task3 = FetchDataAsync("url3"); // Aguardando a conclusão de todas as tarefas await Task.WhenAll(task1, task2, task3); Console.WriteLine("Todas as requisições concluídas");}
public async Task<string> GetFirstResponseAsync(){ var task1 = FetchDataAsync("url1"); var task2 = FetchDataAsync("url2"); // Aguardando a primeira tarefa concluída Task<string> completedTask = await Task.WhenAny(task1, task2); return await completedTask;}