Upd:
Reemplace asyncio.ensure_future
con en asyncio.create_task
todas partes si está usando Python> = 3.7 Es una forma más nueva y agradable de generar tareas .
asyncio. Tarea para "disparar y olvidar"
De acuerdo con los documentos de Python asyncio.Task
, es posible iniciar algunas corrutinas para ejecutar "en segundo plano" . La tarea creada por la asyncio.ensure_future
función no bloqueará la ejecución (¡por lo tanto, la función regresará inmediatamente!). Esto parece una forma de "disparar y olvidar" como lo solicitó.
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())
Salida:
Do some actions 1
async_foo started
Do some actions 2
async_foo done
Do some actions 3
¿Qué sucede si las tareas se ejecutan después de que se completa el ciclo de eventos?
Tenga en cuenta que asyncio espera que la tarea se complete en el momento en que se complete el ciclo de eventos. Entonces, si cambia main()
a:
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')
Recibirá esta advertencia después de que finalice el programa:
Task was destroyed but it is pending!
task: <Task pending coro=<async_foo() running at [...]
Para evitarlo, puede esperar todas las tareas pendientes una vez completado el ciclo 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))
Mata tareas en lugar de esperarlas
A veces, no desea esperar a que se realicen tareas (por ejemplo, es posible que algunas tareas se creen para ejecutarse para siempre). En ese caso, puede cancelarlos () en lugar de esperarlos:
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)
Salida:
Do some actions 1
echo
Do some actions 2
echo
Do some actions 3
echo