
Passo 1 de 8
Da corrotina à tarefa agendada
Diferencie criar uma corrotina, agendá-la como tarefa e aguardar seu resultado.
Trilha de aprendizado · Nível 13 · Tutorial 7
Ao concluir, você será capaz de iniciar corrotinas como tarefas concorrentes, observar seus resultados e solicitar cancelamento preservando a limpeza de recursos.
Da corrotina à tarefa agendada
Diferencie criar uma corrotina, agendá-la como tarefa e aguardar seu resultado. 2 min
Agendar várias tarefas antes de aguardar
Agende o conjunto de corrotinas primeiro e só então observe os resultados, permitindo que elas avancem de forma concorrente. 2 min
Manter referências e observar os desfechos
Guarde as tarefas que você cria e observe cada resultado ou falha antes de encerrar a corrotina coordenadora. 3 min
Entender o pedido de cancelamento
Entenda por que cancelar uma Task é um pedido cooperativo e quando esse pedido pode ser processado. 2 min
Cancelar, aguardar e confirmar
Solicite o cancelamento de uma tarefa, aguarde seu desfecho e diferencie término comum de cancelamento efetivado. 3 min
Limpar recursos e preservar o cancelamento
Use limpeza garantida na corrotina e deixe o cancelamento continuar até quem solicitou a parada. 3 min
Acompanhar a propagação entre tarefas
Identifique como uma dependência ativa de await pode encaminhar um pedido de cancelamento e onde cada corrotina deve preservar sua limpeza. 2 min
Aplicação final: encerrar sem abandonar tarefas
Integre agendamento concorrente, observação de resultado e falha, cancelamento e limpeza em um script local completo. 4 min

Passo 1 de 8
Diferencie criar uma corrotina, agendá-la como tarefa e aguardar seu resultado.
Você já sabe que chamar uma função definida com async def cria um objeto corrotina: o corpo da função ainda não começa a rodar.
Para colocá-la sob controle do laço de eventos, use asyncio.create_task(corrotina). Essa chamada devolve uma Task: um objeto aguardável que acompanha a execução e, depois, seu resultado ou desfecho.
create_task agenda; ele não espera a conclusão.

Criação, agendamento e espera são operações diferentes.
create_task deve ser chamado enquanto há um laço de eventos em execução — por exemplo, dentro de principal. Guarde o retorno em uma variável para então aguardá-lo.
import asyncio
async def buscar_status() -> str:
await asyncio.sleep(1)
return "status recebido"
async def principal() -> None:
corrotina = buscar_status() # cria o objeto corrotina
tarefa = asyncio.create_task(corrotina) # agenda e devolve uma Task
print("tarefa agendada")
resultado = await tarefa # espera o desfecho e obtém o resultado
print(resultado)
asyncio.run(principal())Dica
Ao chegar em create_task, a tarefa fica apta a progredir quando o laço de eventos tiver oportunidade. A linha seguinte não prova que ela já terminou. Somente await tarefa espera seu desfecho e entrega o valor retornado por buscar_status.
Relacione cada operação ao efeito principal.
Toque em um item e depois no par correspondente.

Passo 2 de 8
Agende o conjunto de corrotinas primeiro e só então observe os resultados, permitindo que elas avancem de forma concorrente.
Depois de criar uma Task com asyncio.create_task(...), ela pode progredir quando o laço de eventos tiver oportunidade. Se você cria uma tarefa e já faz await nela antes de criar a próxima, a segunda ainda nem foi agendada.
Para iniciar operações concorrentes, crie as Tasks do conjunto primeiro. Em seguida, aguarde as referências que você guardou.
A diferença está no momento em que cada operação entra no laço de eventos.

À esquerda, cada espera adia o agendamento seguinte. À direita, as duas Tasks já existem antes da primeira observação de resultado.
Cada chamada de create_task devolve imediatamente uma referência à Task agendada.
import asyncio
async def buscar(nome: str, pausa: float) -> str:
print(f"{nome}: iniciada")
await asyncio.sleep(pausa)
print(f"{nome}: concluída")
return f"resultado de {nome}"
async def main() -> None:
tarefa_a = asyncio.create_task(buscar("A", 0.3))
tarefa_b = asyncio.create_task(buscar("B", 0.1))
resultado_a = await tarefa_a
resultado_b = await tarefa_b
print(resultado_a)
print(resultado_b)
asyncio.run(main())Dica
Salve o código em um arquivo .py e execute-o. Os valores de pausa servem apenas para tornar o exemplo visível: não use a ordem nem a duração dos registros como uma garantia do escalonador.
No exemplo, await tarefa_a observa primeiro o desfecho de A. Mas B já foi agendada e pode concluir antes de A enquanto main está suspensa.
Assim, a ordem dos awaits determina a ordem em que este código observador recebe os resultados. Ela não determina a ordem em que Tasks já agendadas concluem.
Exemplo
Uma execução pode mostrar:
A: iniciada → B: iniciada → B: concluída → A: concluída → resultado de A → resultado de B
Mesmo com B concluindo antes, main só imprime o resultado de B depois de receber o de A, porque aguarda tarefa_a primeiro.
Organize os blocos para agendar A e B antes de observar seus resultados.
Por que tarefa_b pode concluir antes de tarefa_a mesmo quando o código usa await tarefa_a antes de await tarefa_b?
Escreva pelo menos 40 caracteres (0/40).

Passo 3 de 8
Guarde as tarefas que você cria e observe cada resultado ou falha antes de encerrar a corrotina coordenadora.
Depois de criar uma Task, mantenha uma referência forte a ela — em uma variável ou em uma coleção — enquanto seu desfecho ainda importa. O laço de eventos mantém referências fracas às Tasks, então não trate uma Task sem referência própria como trabalho acompanhado.
Mas guardar a referência não basta: você precisa observar o desfecho. Ao usar await tarefa, recebe o valor retornado ou a exceção produzida pela corrotina.
Uma coleção mantém as Tasks acessíveis; os awaits recuperam o desfecho de cada uma.

Guardar permite acompanhar; aguardar revela sucesso ou falha.
Atenção
Uma mensagem como “Task exception was never retrieved” é um indício de que uma Task falhou e ninguém recuperou sua exceção. Não dependa do instante em que esse aviso aparece: organize o código para observar explicitamente todos os desfechos relevantes.
Tasks criadas separadamente não são canceladas automaticamente porque uma delas falhou. Se uma falha é esperada e você quer continuar acompanhando as demais, trate essa falha no ponto em que aguarda aquela Task e prossiga para as outras.
Execute este script localmente. A ordem das mensagens pode variar, mas os três desfechos devem ser observados.
import asyncio
async def operacao(nome: str) -> str:
await asyncio.sleep(0.1)
if nome == "validar":
raise ValueError("dados inválidos")
return f"resultado de {nome}"
async def main() -> None:
tarefas = [
asyncio.create_task(operacao("baixar")),
asyncio.create_task(operacao("validar")),
asyncio.create_task(operacao("salvar")),
]
for tarefa in tarefas:
try:
resultado = await tarefa
except ValueError as erro:
print(f"falha observada: {erro}")
else:
print(f"sucesso observado: {resultado}")
asyncio.run(main())Dica
A lista preserva as três referências. O laço não interrompe as observações ao encontrar ValueError: ele registra a falha daquela Task e continua aguardando as restantes. Não há promessa de ordem global de execução; aqui, a ordem de observação é a ordem da lista.
Três Tasks já foram criadas e guardadas em tarefas. A primeira pode lançar ValueError, mas as outras duas ainda precisam ter seus desfechos observados. Qual organização atende a esse objetivo?

Passo 4 de 8
Entenda por que cancelar uma Task é um pedido cooperativo e quando esse pedido pode ser processado.
task.cancel() solicita que a Task seja cancelada. A chamada não confirma que ela já parou, nem que seu desfecho já é conhecido.
No asyncio, o cancelamento é cooperativo: a corrotina precisa voltar ao controle do laço de eventos para receber esse pedido. Até lá, a Task pode continuar pendente ou até terminar por outro motivo.
A solicitação e o cancelamento efetivo são estados diferentes.

O pedido feito por cancel() só pode ser efetivado quando a corrotina tem uma oportunidade de retomar sob controle do laço.
Exemplo
tarefa.cancel()
print(tarefa.done())Logo após cancel(), done() pode ainda ser False. Isso significa apenas que o desfecho da Task ainda não foi concluído e observado.
Quando a Task volta a uma oportunidade de suspensão ou retomada controlada pelo laço — por exemplo, em torno de um await — o asyncio pode entregar asyncio.CancelledError à corrotina.
Assim, uma Task que já começou pode receber um pedido de cancelamento. Isso contrasta com um trabalho que já está em execução em um executor, que não pode ser interrompido dessa forma por Future.cancel().
Atenção
cancel() não interrompe à força código síncrono bloqueante nem um cálculo longo que não oferece suspensão. Enquanto esse código ocupa a thread do laço, o laço não avança para entregar o pedido de cancelamento.
Evite concluir que uma chamada a cancel() torna imediatamente responsiva uma Task que bloqueia o laço.
Depois de chamar task.cancel(), é garantido que a Task já terminou cancelada quando a chamada retorna.
Uma Task que executa processamento longo sem await pode atrasar a efetivação de um pedido de cancelamento.

Passo 5 de 8
Solicite o cancelamento de uma tarefa, aguarde seu desfecho e diferencie término comum de cancelamento efetivado.
task.cancel() faz um pedido cooperativo; ele não confirma que a tarefa já terminou. Depois do pedido, mantenha a referência e faça await task para observar o desfecho.
Quando o cancelamento é efetivado, esse await propaga asyncio.CancelledError para quem está observando a tarefa. Nesse cenário, o observador que pediu o cancelamento pode capturar especificamente essa confirmação.
A consulta de estado complementa a espera, mas não a substitui.

Peça o cancelamento, aguarde a Task e então interprete seu estado final.
Execute este script localmente com Python 3.
import asyncio
async def operacao() -> None:
while True:
print("trabalhando")
await asyncio.sleep(1)
async def main() -> None:
task = asyncio.create_task(operacao())
await asyncio.sleep(0.1)
task.cancel()
try:
await task
except asyncio.CancelledError:
print("cancelamento confirmado")
print(f"done={task.done()}, cancelled={task.cancelled()}")
asyncio.run(main())Dica
asyncio.CancelledError herda de BaseException. Portanto, except Exception: não a captura. Capture asyncio.CancelledError de forma explícita quando você estiver confirmando o cancelamento que solicitou.
Ela também é diferente de concurrent.futures.CancelledError: importe e capture a classe do mecanismo que produziu a exceção. Aqui, a classe correta é asyncio.CancelledError.
task.done() é True quando a Task chegou a qualquer desfecho: retorno normal, exceção ou cancelamento. Já task.cancelled() só é True se ela realmente terminou cancelada.
Não fique consultando esses métodos em um laço para esperar. await task é a sincronização que permite observar o desfecho. Mesmo que a tarefa já tenha acabado antes de cancel(), ainda faça await task: ela pode ter retornado um valor ou produzido outra exceção.
Após task.cancel(), use await ____ para observar o desfecho da tarefa.
Depois de aguardar uma Task, qual condição indica especificamente que ela terminou por cancelamento efetivado?
Por que except Exception não confirma o cancelamento e por que task.done() sozinho não basta para saber que uma tarefa foi cancelada?
Escreva pelo menos 40 caracteres (0/40).

Passo 6 de 8
Use limpeza garantida na corrotina e deixe o cancelamento continuar até quem solicitou a parada.
Quando uma corrotina adquire um recurso, coloque o uso desse recurso dentro de um try e a liberação no finally. O finally é executado tanto na conclusão normal quanto quando asyncio.CancelledError sai do bloco.
A regra é: adquira o recurso antes do try e entre imediatamente no bloco protegido. Assim, depois que usar_recurso() começou, liberar_recurso() será chamado antes de a corrotina terminar.
O pedido de cancelamento não elimina a etapa de limpeza: ele faz a corrotina sair pelo finally, que libera o recurso, e só então o cancelamento chega ao observador.

O finally fica entre a saída do trabalho e a confirmação do cancelamento ao chamador.
O raise sem argumentos relança a mesma exceção de cancelamento após qualquer ação específica.
import asyncio
async def usar_recurso() -> None:
recurso = "conexão simulada"
print(f"adquiri: {recurso}")
try:
print("usando recurso")
await asyncio.sleep(10)
finally:
print(f"liberei: {recurso}")
async def principal() -> None:
tarefa = asyncio.create_task(usar_recurso())
await asyncio.sleep(0)
tarefa.cancel()
try:
await tarefa
except asyncio.CancelledError:
print("cancelamento confirmado no chamador")
asyncio.run(principal())A tarefa que recebeu o cancelamento deve limpar o que lhe pertence e permitir que CancelledError continue. Já o chamador que pediu o cancelamento pode capturar especificamente essa exceção ao fazer await tarefa, pois ali ele está confirmando o desfecho esperado.
Se a própria tarefa captura CancelledError e faz return, ela aparenta ter terminado com sucesso. O mesmo risco existe com um return dentro de finally: ele substitui a exceção que estava sendo propagada.
Atenção
Evite estes padrões:
except asyncio.CancelledError:
liberar_recurso()
return # transforma cancelamento em retorno normalfinally:
liberar_recurso()
return # também impede a propagação de CancelledErrorSe precisar de uma ação exclusiva para cancelamento, faça-a e use raise sem argumentos.
Este formato é útil quando o cancelamento exige um registro ou uma ação adicional antes da limpeza geral.
async def usar_recurso() -> None:
recurso = "conexão simulada"
print(f"adquiri: {recurso}")
try:
await asyncio.sleep(10)
except asyncio.CancelledError:
print("cancelamento recebido; preparando encerramento")
raise
finally:
print(f"liberei: {recurso}")No seu computador, salve o script abaixo como cancelar_recurso.py e execute python cancelar_recurso.py. Ele usa apenas a biblioteca padrão e um recurso simulado.
A ordem exata de todos os registros não é o foco. Verifique estas evidências: o recurso é adquirido, começa a ser usado, é liberado após o pedido de cancelamento e o chamador confirma CancelledError.
A pausa curta em principal() apenas dá uma oportunidade para a tarefa começar antes do pedido; ela não é uma garantia de duração.
import asyncio
async def processar_arquivo() -> None:
arquivo = "relatorio.csv (simulado)"
print(f"abri: {arquivo}")
try:
print("processamento iniciado")
await asyncio.sleep(10)
print("processamento concluído")
except asyncio.CancelledError:
print("cancelamento recebido no processamento")
raise
finally:
print(f"fechei: {arquivo}")
async def principal() -> None:
tarefa = asyncio.create_task(processar_arquivo())
await asyncio.sleep(0)
print("solicitando cancelamento")
tarefa.cancel()
try:
await tarefa
except asyncio.CancelledError:
print("cancelamento confirmado no chamador")
asyncio.run(principal())Depois de executar o script, quais registros mostram que o recurso foi liberado e que o cancelamento continuou até o chamador? Explique em uma ou duas frases.
Escreva pelo menos 80 caracteres (0/80).
Por que adquirir um recurso muito antes de entrar no try reduz a garantia de limpeza do finally?
Escreva pelo menos 80 caracteres (0/80).

Passo 7 de 8
Identifique como uma dependência ativa de await pode encaminhar um pedido de cancelamento e onde cada corrotina deve preservar sua limpeza.
create_task() cria uma tarefa independente, mas não cria por si só uma regra de cancelamento entre quem criou e quem foi criada. A relação relevante surge quando uma tarefa fica suspensa em await outra_task.
Se a tarefa aguardante receber cancelamento enquanto espera, o pedido pode ser encaminhado à tarefa aguardada. Assim, ambas precisam estar preparadas para sair: a aguardada limpa seus próprios recursos e propaga CancelledError; a aguardante também executa sua própria limpeza e continua propagando o cancelamento.
Compare as setas: criar uma tarefa registra responsabilidade de acompanhamento; aguardar uma tarefa cria uma dependência ativa durante aquele await.

Somente a espera ativa com await pode encaminhar o cancelamento à tarefa aguardada.
Dica
Mesmo quando o cancelamento é encaminhado, mantenha referências e observe os desfechos das tarefas que você criou. Propagação de cancelamento não substitui a responsabilidade de acompanhar uma tarefa.
Execute este script localmente. Ele cancela a coordenadora enquanto ela está em await trabalhadora; observe que os dois blocos finally são alcançados.
import asyncio
async def trabalhadora() -> None:
print("trabalhadora: recurso adquirido")
try:
await asyncio.sleep(10)
finally:
print("trabalhadora: recurso liberado")
async def coordenadora() -> None:
tarefa_trabalhadora = asyncio.create_task(trabalhadora())
try:
print("coordenadora: aguardando trabalhadora")
await tarefa_trabalhadora
finally:
print("coordenadora: limpeza concluída")
async def principal() -> None:
tarefa_coordenadora = asyncio.create_task(coordenadora())
await asyncio.sleep(0) # dá oportunidade para a coordenadora iniciar
tarefa_coordenadora.cancel()
try:
await tarefa_coordenadora
except asyncio.CancelledError:
print("principal: cancelamento da coordenadora confirmado")
asyncio.run(principal())
principal() confirma o cancelamento que ela solicitou à coordenadora. Dentro de coordenadora(), porém, não há um except asyncio.CancelledError que termine normalmente: o finally limpa e a exceção continua seu caminho.
A trabalhadora também não suprime o cancelamento. Sua limpeza acontece no finally, e CancelledError volta para a coordenadora. A ordem exata das mensagens pode variar, mas as duas limpezas devem ocorrer antes da confirmação em principal().
Atenção
Se a própria coordenadora recebe CancelledError, capturá-lo e fazer return normalmente transforma um cancelamento em aparente sucesso. Capture-o dentro da coordenadora apenas se precisar de uma ação específica e, depois, use raise sem argumentos para preservá-lo.
Relacione cada situação ao efeito mais adequado.
Toque em um item e depois no par correspondente.
Resumo
Antes de cancelar, desenhe quem criou quem e quem está aguardando quem no momento.
create_task() cria uma tarefa, mas não forma uma árvore automática de cancelamento.await outra_task pode encaminhar à outra um cancelamento que recebeu.
Passo 8 de 8
Integre agendamento concorrente, observação de resultado e falha, cancelamento e limpeza em um script local completo.
Neste fechamento, você vai executar um script com três Tasks independentes: uma retorna um resultado, uma falha de modo esperado e outra é cancelada durante o uso de um recurso simulado.
O objetivo não é obter uma ordem exata de mensagens. Como as tarefas progridem concorrentemente, a ordem pode variar. Confirme, porém, estas evidências:
Mesmo depois de observar a falha de uma Task, a função coordenadora deve continuar responsável pelas outras referências que criou.
Cada seta representa uma responsabilidade explícita: criar e guardar, observar o desfecho e, para a tarefa restante, cancelar e aguardar.

A falha de uma Task criada separadamente não elimina a obrigação de acompanhar as demais.
No seu computador, crie um arquivo chamado encerrar_tarefas.py, copie o código completo abaixo e execute python encerrar_tarefas.py. Ele usa somente a biblioteca padrão.
Três Tasks são agendadas antes de qualquer espera. A coordenadora observa cada desfecho e encerra explicitamente a tarefa longa.
import asyncio
async def buscar_resumo() -> str:
await asyncio.sleep(0.05)
return "resumo pronto"
async def carregar_configuracao() -> str:
await asyncio.sleep(0.02)
raise ValueError("configuração inválida")
async def acompanhar_eventos() -> None:
recurso_aberto = False
try:
recurso_aberto = True
print("eventos: recurso adquirido")
while True:
await asyncio.sleep(1)
finally:
if recurso_aberto:
print("eventos: recurso liberado")
async def main() -> None:
resumo_task = asyncio.create_task(buscar_resumo())
config_task = asyncio.create_task(carregar_configuracao())
eventos_task = asyncio.create_task(acompanhar_eventos())
try:
resumo = await resumo_task
print(f"resultado observado: {resumo}")
except Exception as erro:
print(f"falha inesperada no resumo: {erro}")
try:
await config_task
except ValueError as erro:
print(f"falha observada: {erro}")
eventos_task.cancel()
try:
await eventos_task
except asyncio.CancelledError:
print("cancelamento confirmado")
asyncio.run(main())Dica
cancel() apenas solicita o cancelamento. O await eventos_task dá oportunidade para a corrotina receber CancelledError, executar o finally e propagar o cancelamento; o observador então o confirma com uma captura específica.
Você deve encontrar mensagens equivalentes a estas, embora a posição de eventos: recurso adquirido possa variar:
eventos: recurso adquirido
resultado observado: resumo pronto
falha observada: configuração inválida
eventos: recurso liberado
cancelamento confirmadoO finally em acompanhar_eventos() libera o recurso antes de await eventos_task terminar com CancelledError. A tarefa não transforma o cancelamento em retorno normal: ela deixa a exceção continuar até quem solicitou o cancelamento.
Depois de executar o script, explique como você observou: o resultado, a falha esperada, a limpeza e o cancelamento. Por que apenas chamar eventos_task.cancel() seria insuficiente?
Escreva pelo menos 180 caracteres (0/180).
Resumo
Use esta sequência sempre que criar Tasks separadamente e precisar coordená-las manualmente.
asyncio.create_task() e mantenha referências enquanto seus desfechos importarem.await; uma falha esperada em uma Task não acompanha automaticamente as outras.cancel() e depois faça await nela.finally para liberar recursos adquiridos no bloco protegido.asyncio.CancelledError dentro da tarefa sem uma decisão explícita; após limpeza, ele deve continuar se propagando.Parabéns! Você concluiu: Gerenciar tarefas e cancelamento no asyncio
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks