3

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()

2 Answers 2

5

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())
Sign up to request clarification or add additional context in comments.

6 Comments

can't use asyncio.run as require higher python version as I have.
@eSlavko You can easily replace asyncio.run(main()) with asyncio.get_event_loop().run_until_complete(main()) and everything else can stay the same.
that's doesn't work. It throws error. asyncio.create_task(rxer()) AttributeError: module 'asyncio' has no attribute 'create_task'
@eSlavko I've now amended the answer to create task in a way which works with older Python.
still doesnt work. asyncio.create_task(WsServe(stop_event)) AttributeError: module 'asyncio' has no attribute 'create_task'
|
-1

Check commented lines of your implementation as below:

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()

And here is the output:

Rxer  1
WsServe 0
Rxer  2
WsServe 1
Rxer  3
WsServe 2
Rxer  4
WsServe 3
Rxer  5
WsServe 4
Rxer  6
Finish

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.