When using asyncio, how do you allow all running tasks to finish before shutting down the event loop When using asyncio, how do you allow all running tasks to finish before shutting down the event loop python python

When using asyncio, how do you allow all running tasks to finish before shutting down the event loop


You can retrieve unfinished tasks and run the loop again until they finished, then close the loop or exit your program.

pending = asyncio.all_tasks()loop.run_until_complete(asyncio.gather(*pending))
  • pending is a list of pending tasks.
  • asyncio.gather() allows to wait on several tasks at once.

If you want to ensure all the tasks are completed inside a coroutine (maybe you have a "main" coroutine), you can do it this way, for instance:

async def do_something_periodically():    while True:        asyncio.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())

Also, in this case, since all the tasks are created in the same coroutine, you already have access to the tasks:

async def do_something_periodically():    tasks = []    while True:        tasks.append(asyncio.create_task(my_expensive_operation()))        await asyncio.sleep(my_interval)        if shutdown_flag_is_set:            print("Shutting down")            break    await asyncio.gather(*tasks)


As of Python 3.7 the above answer uses multiple deprecated APIs (asyncio.async and Task.all_tasks,@asyncio.coroutine, yield from, etc.) and you should rather use this:

import asyncioasync def my_expensive_operation(expense):    print(await asyncio.sleep(expense, result="Expensive operation finished."))async def do_something_periodically(expense, interval):    while True:        asyncio.create_task(my_expensive_operation(expense))        await asyncio.sleep(interval)loop = asyncio.get_event_loop()coro = do_something_periodically(1, 1)try:    loop.run_until_complete(coro)except KeyboardInterrupt:    coro.close()    tasks = asyncio.all_tasks(loop)    expensive_tasks = {task for task in tasks if task._coro.__name__ != coro.__name__}    loop.run_until_complete(asyncio.gather(*expensive_tasks))


Use a wrapper coroutine that waits until the pending task count is 1 before returning.

async def loop_job():    asyncio.create_task(do_something_periodically())    while len(asyncio.Task.all_tasks()) > 1:  # Any task besides loop_job() itself?        await asyncio.sleep(0.2)asyncio.run(loop_job())