run - process async python
Al usar asyncio, ¿cómo permite que finalicen todas las tareas en ejecución antes de apagar el bucle de eventos? (2)
Tengo el siguiente código:
@asyncio.coroutine
def do_something_periodically():
while True:
asyncio.async(my_expensive_operation())
yield from asyncio.sleep(my_interval)
if shutdown_flag_is_set:
print("Shutting down")
break
Ejecuto esta función hasta que esté completo. El problema ocurre cuando se establece el apagado: la función se completa y las tareas pendientes nunca se ejecutan. (Usted ve esto como un error
task: <Task pending coro=<report() running at script.py:33> wait_for=<Future pending cb=[Task._wakeup()]>>
) ¿Cómo programo un cierre correctamente?
Para dar algún contexto, estoy escribiendo un monitor del sistema que lee de / proc / stat cada 5 segundos, calcula el uso de la CPU en ese período y luego envía el resultado a un servidor. Deseo seguir programando estos trabajos de supervisión hasta que reciba sigterm, cuando dejo de programar, espero a que terminen todos los trabajos actuales y salgo con elegancia.
A partir de Python 3.7, la respuesta anterior usa varias API en desuso (asyncio.async y Task.all_tasks, @ asyncio.coroutine, yield from, etc.) y debería usar esto:
import asyncio
my_interval = 1
shutdown_flag_is_set = False
async def my_expensive_operation():
print(await asyncio.sleep(10, result="Expensive operation finished."))
async def do_something_periodically(*, loop):
global shutdown_flag_is_set
while True:
loop.create_task(my_expensive_operation())
await asyncio.sleep(my_interval)
if shutdown_flag_is_set:
print("Shutting down")
break
await asyncio.gather(*asyncio.all_tasks(loop))
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(do_something_periodically(loop=loop))
except KeyboardInterrupt:
shutdown_flag_is_set = True
Puede recuperar tareas sin terminar y ejecutar el ciclo de nuevo hasta que finalicen, luego cierre el ciclo o salga de su programa.
pending = asyncio.Task.all_tasks()
loop.run_until_complete(asyncio.gather(*pending))
- pendiente es una lista de tareas pendientes.
- asyncio.gather () permite esperar en varias tareas a la vez.
Si quiere asegurarse de que todas las tareas se completen dentro de una corutina (tal vez tenga una corutina "principal"), puede hacerlo de esta manera, por ejemplo:
@asyncio.coroutine
def do_something_periodically():
while True:
asyncio.async(my_expensive_operation())
yield from asyncio.sleep(my_interval)
if shutdown_flag_is_set:
print("Shutting down")
break
yield from asyncio.gather(*asyncio.Task.all_tasks())
Además, en este caso, dado que todas las tareas se crean en la misma coroutine, ya tiene acceso a las tareas:
@asyncio.coroutine
def do_something_periodically():
tasks = []
while True:
tasks.append(asyncio.async(my_expensive_operation()))
yield from asyncio.sleep(my_interval)
if shutdown_flag_is_set:
print("Shutting down")
break
yield from asyncio.gather(*tasks)