Upd:
Substitua asyncio.ensure_future
por asyncio.create_task
qualquer lugar se estiver usando Python> = 3.7. É uma maneira mais nova e mais agradável de gerar tarefas .
asyncio. Peça para “disparar e esquecer”
De acordo com a documentação do python asyncio.Task
, é possível iniciar alguma co-rotina para executar "em segundo plano" . A tarefa criada pela asyncio.ensure_future
função não bloqueará a execução (portanto, a função retornará imediatamente!). Parece uma forma de “disparar e esquecer” conforme solicitado.
import asyncio
async def async_foo():
print("async_foo started")
await asyncio.sleep(1)
print("async_foo done")
async def main():
asyncio.ensure_future(async_foo()) # fire and forget async_foo()
# btw, you can also create tasks inside non-async funcs
print('Do some actions 1')
await asyncio.sleep(1)
print('Do some actions 2')
await asyncio.sleep(1)
print('Do some actions 3')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Resultado:
Do some actions 1
async_foo started
Do some actions 2
async_foo done
Do some actions 3
E se as tarefas estiverem sendo executadas após a conclusão do loop de evento?
Observe que asyncio espera que a tarefa seja concluída no momento em que o loop de eventos for concluído. Então, se você mudar main()
para:
async def main():
asyncio.ensure_future(async_foo()) # fire and forget
print('Do some actions 1')
await asyncio.sleep(0.1)
print('Do some actions 2')
Você receberá este aviso após a conclusão do programa:
Task was destroyed but it is pending!
task: <Task pending coro=<async_foo() running at [...]
Para evitar isso, você pode apenas aguardar todas as tarefas pendentes após a conclusão do loop de eventos:
async def main():
asyncio.ensure_future(async_foo()) # fire and forget
print('Do some actions 1')
await asyncio.sleep(0.1)
print('Do some actions 2')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
# Let's also finish all running tasks:
pending = asyncio.Task.all_tasks()
loop.run_until_complete(asyncio.gather(*pending))
Mate tarefas em vez de esperá-las
Às vezes, você não quer esperar que as tarefas sejam realizadas (por exemplo, algumas tarefas podem ser criadas para serem executadas para sempre). Nesse caso, você pode simplesmente cancelá-los () em vez de aguardá-los:
import asyncio
from contextlib import suppress
async def echo_forever():
while True:
print("echo")
await asyncio.sleep(1)
async def main():
asyncio.ensure_future(echo_forever()) # fire and forget
print('Do some actions 1')
await asyncio.sleep(1)
print('Do some actions 2')
await asyncio.sleep(1)
print('Do some actions 3')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
# Let's also cancel all running tasks:
pending = asyncio.Task.all_tasks()
for task in pending:
task.cancel()
# Now we should await task to execute it's cancellation.
# Cancelled task raises asyncio.CancelledError that we can suppress:
with suppress(asyncio.CancelledError):
loop.run_until_complete(task)
Resultado:
Do some actions 1
echo
Do some actions 2
echo
Do some actions 3
echo