Domine inglês técnico de programação em 2025, seja qual for seu nível. Inscrição gratuita
Programação assíncrona em C#: task, await e concorrência
Rocketseat
Navegação Rápida:
Já imaginou escrever código que se parece com uma sequência simples de instruções, mas executa tarefas de forma eficiente e sem bloqueios? Bem-vindo ao mundo da programação assíncrona em C#! Hoje, vamos explorar como Task, await e técnicas de concorrência podem transformar a maneira como você desenvolve aplicações.
O que é programação assíncrona e por que ela é importante?
A programação assíncrona é uma abordagem que permite que um programa continue executando outras tarefas enquanto aguarda a conclusão de operações demoradas, como leitura de arquivos, chamadas de API ou consultas a banco de dados. Isso resolve gargalos de I/O e melhora a responsividade de aplicações desktop e web.
Imagine pedir um café em uma cafeteria movimentada. Você faz o pedido, senta-se e começa a responder e-mails enquanto espera ser chamado. Essa é uma analogia perfeita para o assíncronismo: tarefas sendo realizadas em paralelo, mas sem bloqueio.
Na programação síncrona, o código espera que cada etapa seja concluída antes de prosseguir, o que pode ser ineficiente. Com a programação assíncrona, você pode iniciar várias tarefas simultaneamente e gerenciá-las de forma eficaz.
Os pilares: task e await
Task: o que é e como utilizá-la
No C#, uma Task representa uma operação que pode estar em execução ou ser agendada para execução. Ela é a base da programação assíncrona no .NET. Você pode criar uma Task de várias formas, como:
Task tarefa = Task.Run(() => { Console.WriteLine("Executando tarefa..."); });
As Tasks têm estados bem definidos:
- Created: quando a tarefa foi criada, mas ainda não iniciada.
- Running: a tarefa está sendo executada.
- RanToCompletion: finalizou com sucesso.
- Faulted ou Canceled: ocorreu um erro ou foi cancelada.
Você também pode criar Tasks que retornam valores usando
Task<T>
:Task<int> resultado = Task.Run(() => 42); Console.WriteLine($"Resultado: {resultado.Result}");
await: simplificando o assíncronismo
A palavra-chave await permite que você pause a execução de um método até que uma Task seja concluída, sem bloquear a thread chamadora. Por exemplo:
async Task ExemploAsync() { Console.WriteLine("Iniciando..."); await Task.Delay(2000); Console.WriteLine("Finalizado!"); }
Oawait
só pode ser usado em métodos marcados comasync
, sinalizando que eles podem conter operações assíncronas.
Concatenando e orquestrando tasks
Um dos maiores benefícios da programação assíncrona é a capacidade de executar múltiplas tarefas simultaneamente. O .NET fornece métodos como
Task.WhenAll
e Task.WhenAny
para orquestrar essas tarefas.Executando tarefas em paralelo com Task.WhenAll
Se você precisa esperar por várias operações, como downloads de arquivos, pode usar
Task.WhenAll
:var tarefa1 = Task.Delay(3000); var tarefa2 = Task.Delay(2000); await Task.WhenAll(tarefa1, tarefa2); Console.WriteLine("Ambas as tarefas concluídas!");
Aguardando a primeira tarefa com Task.WhenAny
Caso precise agir assim que a primeira tarefa for concluída,
Task.WhenAny
é a escolha certa:var tarefas = new[] { Task.Delay(3000), Task.Delay(2000) }; var primeiraConcluida = await Task.WhenAny(tarefas); Console.WriteLine("Uma tarefa foi concluída!");
Tratamento de exceções em código assíncrono
Erros em código assíncrono podem ser capturados com blocos
try-catch
, garantindo que o aplicativo lide bem com falhas:try { await Task.Run(() => throw new InvalidOperationException("Erro!")); } catch (Exception ex) { Console.WriteLine($"Exceção capturada: {ex.Message}"); }
Quando você usa
Task.WhenAll
, exceções múltiplas podem ocorrer. Nesse caso, elas são encapsuladas em um AggregateException
, que precisa ser tratado cuidadosamente.Concorrência e paralelismo: qual é a diferença?
- Concorrência: várias tarefas em execução ao mesmo tempo, mas compartilhando os mesmos recursos.
- Paralelismo: tarefas sendo executadas simultaneamente em múltiplos threads ou núcleos.
No .NET, o Thread Pool gerencia as threads de forma eficiente, priorizando operações assíncronas baseadas em I/O para maximizar o desempenho.
Para operações CPU-bound, use
Task.Run
. Já para operações I/O-bound, aproveite o modelo assíncrono com await
.Lidando com recursos compartilhados
Problemas de concorrência, como race conditions (condições de corrida) e deadlocks (travamentos), podem surgir quando várias tarefas tentam acessar simultaneamente um recurso compartilhado. Para evitar esses problemas, você pode utilizar mecanismos de sincronização como o SemaphoreSlim, que permite gerenciar o acesso exclusivo a esses recursos:
SemaphoreSlim semaphore = new SemaphoreSlim(1); await semaphore.WaitAsync(); try { Console.WriteLine("Acesso exclusivo a um recurso."); } finally { semaphore.Release(); }
O
SemaphoreSlim
cria uma fila ordenada de acesso, garantindo que apenas um determinado número de tarefas possa acessar o recurso ao mesmo tempo. No exemplo acima, limitamos o acesso a uma única tarefa. Isso resolve race conditions e evita conflitos ao manipular recursos compartilhados.Imagine o semaphore como um gerente de fila em uma cafeteria: ele permite que apenas uma pessoa de cada vez use a máquina de café, garantindo ordem e evitando conflitos. Implementar um controle como esse não só melhora a estabilidade do código, mas também evita problemas difíceis de diagnosticar, como resultados inconsistentes ou bloqueios inesperados.
Performance e boas práticas
Evite async void
Métodos
async void
não retornam uma Task
, dificultando o monitoramento de sua execução e o tratamento de erros. Prefira async Task
ou async Task<T>
, pois eles permitem usar await
para rastrear quando uma operação termina e capturar exceções.// Correto: async Task ProcessarDadosAsync() { await Task.Delay(1000); Console.WriteLine("Dados processados!"); }
Use ConfigureAwait(false)
Para operações que não precisam atualizar o contexto de sincronização (como aplicações de biblioteca), usar
ConfigureAwait(false)
melhora o desempenho e evita deadlocks em cenários específicos:await Task.Delay(2000).ConfigureAwait(false);
Essa abordagem é especialmente útil em bibliotecas ou serviços que realizam chamadas assíncronas, pois minimiza a sobrecarga do contexto.
Diagnóstico e monitoramento
A performance de código assíncrono pode ser monitorada com ferramentas como dotTrace ou o Visual Studio Diagnostic Tools. Elas ajudam a identificar gargalos em tarefas assíncronas, analisando o consumo de CPU, tempo de espera e travamentos:
- dotTrace: excelente para identificar operações assíncronas que bloqueiam threads.
- Visual Studio Diagnostic Tools: ideal para depuração em tempo real, mostrando o comportamento do código durante a execução.
Integrar essas ferramentas ao seu fluxo de trabalho garante aplicações mais robustas e de alta performance.
Próximos passos
Agora que você compreendeu os fundamentos e técnicas da programação assíncrona, é hora de transformar teoria em prática. Experimente criar métodos assíncronos, otimize seus projetos e resolva desafios reais do dia a dia. A prática é o segredo para dominar essa habilidade essencial no mercado.
Com mais de 100 horas de conteúdo direto ao ponto, você aprenderá desde os fundamentos do C# e .NET até o desenvolvimento de APIs robustas e bibliotecas organizadas. Tudo isso com o acompanhamento de especialistas como Welisson Arley, que traz experiência prática e insights valiosos para que você se destaque.
O que você vai conquistar ao fazer parte dessa formação?
- Projetos reais para construir um portfólio de brilhar os olhos.
- Certificado reconhecido pelo mercado, validando seu conhecimento.
- Suporte e acompanhamento personalizado para tirar todas as suas dúvidas.
- Networking com uma comunidade incrível de desenvolvedores.
Por que aprender C#?
- Versatilidade: crie aplicativos para web, mobile e até jogos.
- Alta demanda: grandes empresas como Uber, Spotify e Slack utilizam C#.
- Salários competitivos: com níveis que podem chegar a R$ 12 mil para profissionais seniores.
Garanta já a sua vaga e comece a dominar o C#! Não perca a oportunidade de transformar sua carreira com a Rocketseat. Explore mais clicando aqui.
Nos vemos na formação! Continue explorando, experimentando e, acima de tudo, codando.