Módulo 9 - Async e asyncio
O event loop e asyncio.run
9 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Entender o papel coordenador do event loop.
- Usar asyncio.run como porta de entrada do código async.
- Saber por que existe apenas um asyncio.run no topo do programa.
- Visualizar o revezamento entre corrotinas nos pontos de await.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: O event loop e asyncio.run.
Os objetivos desta aula. Entender o papel coordenador do event loop. Usar asyncio.run como porta de entrada do código async. Saber por que existe apenas um asyncio.run no topo do programa. Visualizar o revezamento entre corrotinas nos pontos de await.
Veja o essencial, parte por parte.
O coordenador de tudo. O event loop é o laço que coordena as corrotinas, alternando entre elas nos pontos de await.
asyncio.run, a porta de entrada. Para rodar código assíncrono no Playground do curso, comece a corrotina principal e chame asyncio.run(main()) no fim.
Um detalhe que a próxima aula resolve. Olhe de novo o exemplo anterior.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
O coordenador de tudo
O event loop é o cérebro do asyncio. Pense nele como um laço infinito que mantém uma lista de tarefas e, a cada volta, pergunta: quem está pronto para avançar? Ele escolhe uma corrotina, deixa que ela rode até topar com um await, e nesse ponto a corrotina cede o controle de volta ao loop. O loop então guarda onde ela parou, verifica se alguma espera já terminou e passa a vez à próxima tarefa pronta. Esse vaivém acontece milhares de vezes por segundo, tão rápido que dá a impressão de tudo rodar junto, embora seja sempre um único thread fazendo uma coisa de cada vez.
Você quase nunca controla o event loop na mão. O trabalho de criar, rodar e fechar o loop foi empacotado em uma função só, o asyncio.run, e é ela que você usa. Você passa a sua corrotina principal para o asyncio.run, e ele cuida de iniciar o loop, executar a corrotina do começo ao fim, com todos os seus awaits, e depois fechar o loop de forma limpa, liberando recursos. É a fronteira entre o mundo comum, síncrono, e o mundo assíncrono do seu programa.
asyncio.run, a porta de entrada
A regra de ouro do asyncio.run é que existe um só, no ponto mais alto do programa. Ele é a ponte que leva do código normal para o assíncrono. Uma vez lá dentro, na sua corrotina principal, você não chama asyncio.run de novo; usa await para aguardar outras corrotinas e funções como gather para rodar várias juntas. Tentar aninhar um asyncio.run dentro de código que já roda em um event loop dá erro, porque não se pode iniciar um loop dentro de outro que já está girando. A imagem certa é: uma entrada, muitos awaits lá dentro.
import asyncio
async def tarefa(nome, segundos):
print(f"comeca {nome}")
await asyncio.sleep(segundos)
print(f"termina {nome}")
return nome
async def main():
# dentro do async: aguardamos corrotinas, sem novo asyncio.run
a = await tarefa("A", 1)
b = await tarefa("B", 1)
print("resultados:", a, b)
# uma unica porta de entrada, no topo
asyncio.run(main())asyncio.run(main()) é a única entrada; dentro de main usamos await, não outro run.
Um detalhe que a próxima aula resolve
Olhe de novo o exemplo anterior. As duas tarefas rodam uma após a outra: aguardamos a A terminar para só então começar a B, e o tempo total é a soma das duas. Isso porque await roda a corrotina até o fim antes de seguir para a próxima linha. Ou seja, aguardar corrotinas em sequência não dá concorrência sozinho; dá o mesmo tempo de um código comum. Pode parecer decepcionante, mas é esperado: o await é sobre esperar uma coisa de cada vez. Para que várias tarefas avancem ao mesmo tempo, aproveitando as esperas umas das outras, é preciso agendá-las juntas no event loop.
É aí que entram as tasks e a função asyncio.gather, tema da próxima aula. Elas pegam várias corrotinas e as colocam para girar no loop ao mesmo tempo, de modo que, enquanto a A espera no seu asyncio.sleep, a B já esteja esperando no dela. O tempo total cai para o da tarefa mais demorada, não para a soma. Por agora, o que importa fixar é a arquitetura: o event loop coordena, o asyncio.run é a porta de entrada única, e dentro dele o await controla o fluxo. A concorrência de verdade vem quando damos ao loop várias tarefas para intercalar.
Teste rápido
Qual é o papel do asyncio.run em um programa assíncrono?
Perguntas frequentes
- Posso chamar asyncio.run várias vezes no mesmo programa?
- O padrão é ter um único asyncio.run no topo, que roda a sua corrotina principal do início ao fim. Chamá-lo de novo dentro de código que já executa em um event loop gera erro, porque não se inicia um loop dentro de outro já em execução. Concentre a lógica assíncrona sob uma única entrada.
- O event loop usa vários núcleos do processador?
- Não. O event loop roda em um único thread e faz uma coisa de cada vez, alternando entre corrotinas nos pontos de await. A sensação de simultaneidade vem da rapidez do revezamento, não de paralelismo real. Para usar vários núcleos, o caminho continua sendo processos, como no módulo de threads.
- Preciso criar o event loop manualmente?
- Na prática moderna, não. O asyncio.run cuida de criar, rodar e fechar o loop da forma recomendada. Existe uma API de mais baixo nível para casos avançados, mas para o dia a dia, e para o Playground do curso, o asyncio.run é o suficiente e o mais seguro.
- Por que meu await de duas tarefas em sequência não ficou mais rápido?
- Porque aguardar corrotinas uma após a outra as executa em sequência: a segunda só começa quando a primeira termina. Para que rodem ao mesmo tempo e você ganhe tempo, é preciso agendá-las juntas no loop, com asyncio.gather ou criando tasks, tema da próxima aula.
- O que é uma task no asyncio?
- É uma corrotina agendada para avançar de forma concorrente no event loop. Diferente de só aguardar uma corrotina em sequência, criar uma task faz o loop começar a executá-la assim que tiver folga. As tasks são a base para rodar várias corrotinas ao mesmo tempo, o que a próxima aula explora com gather.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.