async/await e tipos de retorno
ResumoProgramação assíncrona libera threads durante operações de I/O (banco, rede), aumentando a escalabilidade da API. Aqui entendemos
async/await, os tipos de retorno e por que "async por padrão" é a recomendação em ASP.NET Core.
1. Objetivos de Aprendizagem#
- Explicar o que
async/awaitresolve (escalabilidade de I/O). - Escolher os tipos de retorno corretos (
Task,Task<T>,ValueTask). - Entender por que evitar bloqueio síncrono.
2. Pré-requisitos#
- Endpoints GET (Módulo 18).
3. Conceito#
Uma operação de I/O (consulta ao banco) passa a maior parte do tempo esperando. De forma síncrona, a thread fica bloqueada esperando. Com async/await, a thread é liberada para atender outras requisições enquanto o I/O acontece, e retomada quando o resultado chega. O porquê: mais requisições atendidas com o mesmo número de threads = maior throughput.
Task— operação assíncrona sem valor de retorno.Task<T>— operação assíncrona que produz umT.ValueTask<T>— otimização para casos que frequentemente completam de forma síncrona (evita alocação).
4. Mão na Massa#
4.1. Setup#
Sem pacotes; usamos os métodos assíncronos do EF Core (ToListAsync, FirstOrDefaultAsync, SaveChangesAsync).
4.2. Implementação Passo a Passo#
- Método assíncrono de repositório:
public async Task<IEnumerable<Categoria>> GetAllAsync(bool trackChanges) =>
await FindAll(trackChanges).OrderBy(c => c.Nome).ToListAsync();
- Ação assíncrona:
[HttpGet]
public async Task<IActionResult> GetCategorias()
{
var categorias = await _service.Categoria.GetAllAsync(trackChanges: false);
return Ok(categorias);
}
ValueTasknum serviço com cache que costuma responder síncrono:
public ValueTask<CategoriaDto?> GetCachedAsync(Guid id) =>
_cache.TryGetValue(id, out var dto)
? ValueTask.FromResult<CategoriaDto?>(dto)
: new ValueTask<CategoriaDto?>(LoadAsync(id));
4.3. Executando#
O comportamento externo é idêntico; o ganho aparece sob carga, com maior número de requisições simultâneas atendidas.
5. Exemplo Completo#
A pilha inteira deve ser assíncrona: controller → serviço → repositório → EF Core, cada nível com await do nível seguinte.
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
| Assíncrono de ponta a ponta | Misturar chamadas síncronas bloqueantes no meio |
Usar Task/Task nos métodos de I/O | async void (exceto em event handlers) |
Propagar CancellationToken | Ignorar cancelamento em operações longas |
Atenção
async voidengole exceções e não pode ser aguardado — nunca use em métodos de ação ou serviço. UseTask.
7. Segurança e Produção#
- Propagar
CancellationTokenevita trabalho desperdiçado quando o cliente desiste da requisição (economia de recursos e proteção contra abuso).
8. Exercícios#
- Fácil: converta um método de repositório síncrono para
async. - Médio: adicione
CancellationTokenda ação até oToListAsync. - Desafio: explique quando
ValueTasktraz ganho real e quando é prematuro.
9. Resumo#
async/await libera threads durante I/O, aumentando a escalabilidade. Use Task/Task<T>, evite async void e propague CancellationToken.
10. Próximos Passos#
A seguir, refatoramos repositório, serviço e controller para o modelo assíncrono.
11. Referências#
- Microsoft Learn — Programação assíncrona com async e await
- Microsoft Learn — Consultas assíncronas no EF Core
- Microsoft Learn — ValueTask