5 técnicas de Python para orquestração eficiente de recursos em produção
Fazer código Python rodar de forma concorrente é um problema resolvido: asyncio.gather, um pool de threads e alguns await resolvem I/O paralelo numa tarde. O problema mais difícil — o que separa uma demo de algo rodando em produção — é fazer um conjunto finito e limitado de recursos se comportar corretamente sob concorrência. É isso que chamamos de orquestração de recursos.
Contexto que importa
O Python 3.14 (outubro de 2025) trouxe melhorias de thread-safety ao asyncio para suportar o build free-threaded, oficialmente promovido de experimental para suportado sob a PEP 779. O Python 3.15, já em beta, fecha uma lacuna antiga em concorrência estruturada ao adicionar TaskGroup.cancel(). As técnicas abaixo valem para 3.11 em diante, com uma exceção explícita para 3.14.
1. asyncio.TaskGroup (correção estrutural)
O asyncio.gather tem um modo de falha bem documentado: se uma tarefa do grupo lança exceção, as outras não são canceladas automaticamente, e você pode acabar com tarefas órfãs rodando em segundo plano. O asyncio.TaskGroup (Python 3.11) corrige isso por construção: toda tarefa lançada dentro do grupo termina ou é cancelada antes de o bloco async with sair. O TaskGroup resolve a correção da orquestração — mas não diz nada sobre capacidade.
2. asyncio.Semaphore (limite de capacidade)
Sozinho, o código anterior abriria 30 conexões simultâneas a um backend que só aguenta 3. O asyncio.Semaphore é a solução, e a decisão-chave de design é o escopo: um semáforo por backend, dimensionado à capacidade real daquele serviço, compartilhado entre todas as requisições do processo. Em testes com 30 requisições concorrentes, o backend de risco limitado a 3 teve pico de exatamente 3 chamadas em voo — nem uma a mais.
3. AsyncExitStack (contagem dinâmica de recursos)
Empilhar blocos async with funciona quando você sabe quantos recursos abre em tempo de escrita. Quebra quando esse número é decidido em runtime — quais backends estão habilitados pode depender de feature flag ou configuração por tenant. O AsyncExitStack resolve isso: abre um número arbitrário de context managers assíncronos numa pilha e garante que todos fechem, em ordem reversa, na saída.
4. asyncio.timeout (escopo, não chamada)
O asyncio.wait_for era o jeito padrão de dar timeout em uma chamada, mas aninhar múltiplos wait_for fica confuso rápido. O asyncio.timeout() (3.11), como context manager assíncrono, faz do deadline uma propriedade de um escopo, não de uma chamada específica — então um timeout externo pode envolver um TaskGroup inteiro enquanto tarefas individuais têm timeouts próprios e mais apertados.
5. TaskGroup.cancel (Python 3.14)
O TaskGroup.cancel() — a técnica que exige 3.14 — permite cancelar cooperativamente todo o grupo de dentro para fora, algo que bibliotecas como Trio e AnyIO têm desde 2018 e que o Python padrão finalmente incorpora.
A lição de fundo: o que separa uma demo de um sistema em produção não é saber abrir conexões concorrentes, e sim garantir que um conjunto limitado de recursos — APIs de preço, bancos de posições, feeds de notícias, modelos de risco — se comporte corretamente sob carga real.
Descubra mais sobre noticiAI
Assine para receber nossas notícias mais recentes por e-mail.



