Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop asyncio loop with multiple tasks

I can't figure how to stop loop after one task is finished. In sample when WsServe count to 5 I expect loop to close. But instead stop I got RuntimeError: Cannot close a running event loop

#!/usr/bin/env python
import asyncio

async def rxer():
    i=0
    while True:
        i+=1
        print ('Rxer ',i)
        await asyncio.sleep(1)

async def WsServe():
    for i in range(5):
        print ('WsServe',i)
        await asyncio.sleep(1)

    print ('Finish')
    loop.stop()
    loop.close()

loop=asyncio.get_event_loop()
loop.create_task(rxer())
loop.run_until_complete(WsServe())
loop.run_forever()
like image 510
eSlavko Avatar asked May 25 '26 01:05

eSlavko


1 Answers

The error comes from calling loop.close() from inside the loop. You don't need to bother with loop.close(), loop.stop() is quite sufficient to stop the loop. loop.close() is only relevant when you want to ensure that all the resources internally acquired by the loop are released. It is not needed when your process is about to exit anyway, and removing the call to loop.close() indeed eliminates the error.

But also, loop.stop() is incompatible with run_until_complete(). It happens to work in this code because the coroutine returns immediately after calling loop.stop(); if you added e.g. an await asyncio.sleep(1) after loop.stop(), you'd again get a (different) RuntimeError.

To avoid such issues, I suggest that you migrate to the newer asyncio.run API and avoid both run_until_complete and stop. Instead, you can just use an event to terminate the main function, and the loop with it:

# rxer() defined as before

async def WsServe(stop_event):
    for i in range(5):
        print ('WsServe',i)
        await asyncio.sleep(1)

    print ('Finish')
    stop_event.set()
    await asyncio.sleep(1)

async def main():
    asyncio.get_event_loop().create_task(rxer())
    stop_event = asyncio.Event()
    asyncio.get_event_loop().create_task(WsServe(stop_event))
    await stop_event.wait()

asyncio.run(main())

# python 3.6 and older:
#asyncio.get_event_loop().run_until_complete(main())
like image 122
user4815162342 Avatar answered May 27 '26 14:05

user4815162342