Módulo 9 - Async e asyncio

Corrotinas: async def e await

10 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

O que você vai aprender

  • Definir uma corrotina com async def.
  • Usar await para esperar uma operação assíncrona.
  • Entender que chamar uma corrotina devolve um objeto, não o resultado.
  • Reconhecer a semelhança entre corrotinas e geradores.

Escrevendo a primeira corrotina

Uma corrotina se parece com uma função comum, mas começa com async def em vez de só def. Essa palavrinha muda tudo: a função ganha o poder de pausar no meio, nos pontos marcados com await, e ser retomada depois. Dentro da corrotina, você usa await antes de qualquer operação assíncrona que possa demorar, como uma chamada de rede. No exemplo abaixo usamos asyncio.sleep, a versão assíncrona do sleep, para simular uma espera. A diferença crucial em relação ao time.sleep é que o asyncio.sleep não trava tudo: ele cede o controle ao event loop enquanto espera, deixando outras tarefas avançarem.

import asyncio

async def buscar(nome):
    print(f"buscando {nome}")
    await asyncio.sleep(1)   # espera sem travar o loop
    print(f"pronto {nome}")
    return f"dados de {nome}"

async def main():
    resultado = await buscar("perfil")
    print(resultado)

asyncio.run(main())

async def cria a corrotina; await espera o asyncio.sleep sem bloquear o event loop.

Chamar não é executar

O erro mais comum de quem começa com async é chamar uma corrotina como se fosse uma função normal e estranhar que nada acontece. Quando você escreve buscar('perfil') sem await, o Python não roda o corpo da corrotina; ele apenas cria e devolve um objeto corrotina, uma promessa de trabalho que ainda não começou. Para o trabalho acontecer de verdade, você precisa aguardar esse objeto com await, se estiver dentro de outra corrotina, ou entregá-lo ao event loop com asyncio.run, se estiver no nível de cima. Esquecer o await é como escrever o pedido num papel e nunca entregá-lo à cozinha.

import asyncio

async def saudar():
    await asyncio.sleep(0.5)
    return "ola"

async def main():
    x = saudar()          # NAO executa: x e um objeto corrotina
    print(type(x))        # <class 'coroutine'>
    resultado = await x   # agora sim executa e devolve o valor
    print(resultado)      # ola

asyncio.run(main())

saudar() sozinho só cria o objeto corrotina; é o await que dispara a execução.

Parentes dos geradores

Se as corrotinas soam familiares, não é coincidência. Elas descendem diretamente dos geradores que você viu no módulo 7. Um gerador pausa em cada yield e devolve o controle a quem o consome, retomando de onde parou na próxima chamada. Uma corrotina faz algo muito parecido: pausa em cada await e devolve o controle ao event loop, retomando quando a espera termina. A mecânica de suspender e retomar a execução é a mesma raiz. Entender esse parentesco ajuda a desmistificar o async: não é magia nova, é a velha ideia de uma função que consegue parar no meio e continuar depois, agora coordenada por um event loop.

Na prática, isso significa que o seu código assíncrono lê quase como código normal, de cima para baixo, com os awaits marcando onde ele pode pausar. Você não precisa pensar em callbacks nem em encadear funções; escreve a lógica na ordem natural e apenas sinaliza as esperas. Essa legibilidade é uma das grandes vantagens do async moderno sobre estilos antigos de programação assíncrona. Na próxima aula você conhece o event loop de perto e o asyncio.run, a porta de entrada que faz tudo isso girar.

Teste rápido

O que acontece quando você escreve buscar('x') sem await, sendo buscar uma corrotina?

Perguntas frequentes

Posso usar await fora de uma função async?
Não. O await só é válido dentro de uma corrotina, definida com async def. Se você tentar usá-lo em uma função comum ou no nível do módulo, o Python dá erro de sintaxe. A porta de entrada para o mundo assíncrono, a partir de código normal, é o asyncio.run, que você vê na próxima aula.
Qual a diferença entre asyncio.sleep e time.sleep?
O time.sleep bloqueia o thread inteiro: nada mais roda durante a pausa. O asyncio.sleep é assíncrono: ele cede o controle ao event loop enquanto espera, então outras corrotinas avançam. Dentro de código async, use sempre asyncio.sleep para não travar o loop.
Toda função que faz I/O precisa ser async?
Para participar do modelo assíncrono, sim: as operações de espera devem ter versões que você aguarde com await, oferecidas por bibliotecas assíncronas. Uma chamada bloqueante comum dentro de uma corrotina travaria o event loop. Por isso o ecossistema tem clientes assíncronos próprios para rede, banco e afins.
Corrotina e gerador são a mesma coisa?
São parentes próximos, não idênticos. Ambos podem pausar e retomar a execução, o gerador no yield e a corrotina no await. A corrotina é especializada para o modelo assíncrono e trabalha com o event loop. Entender geradores facilita muito a compreensão de corrotinas, porque a mecânica de suspender e continuar é a mesma.
O que significa o aviso coroutine was never awaited?
É o Python avisando que você criou um objeto corrotina, chamando a função async, mas nunca o aguardou nem o agendou, então o trabalho não aconteceu. Quase sempre a correção é acrescentar o await que faltou, ou passar a corrotina para asyncio.run ou para uma função como gather.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.