简体   繁体   English

如何停止具有多个任务的异步循环

[英]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.在示例中,当 WsServe 计数到 5 时,我希望循环关闭。 But instead stop I got RuntimeError: Cannot close a running event loop但是停止我得到了RuntimeError:无法关闭正在运行的事件循环

#!/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()

The error comes from calling loop.close() from inside the loop.错误来自从循环内部调用loop.close() You don't need to bother with loop.close() , loop.stop() is quite sufficient to stop the loop.你并不需要理会loop.close() loop.stop()是相当足以停止循环。 loop.close() is only relevant when you want to ensure that all the resources internally acquired by the loop are released. loop.close()仅当您要确保循环内部获取的所有资源都被释放时才相关。 It is not needed when your process is about to exit anyway, and removing the call to loop.close() indeed eliminates the error.无论如何,当您的进程即将退出时不需要它,并且删除对loop.close()的调用确实消除了错误。

But also, loop.stop() is incompatible with run_until_complete() .而且, loop.stop()run_until_complete()不兼容。 It happens to work in this code because the coroutine returns immediately after calling loop.stop() ;它恰好在这段代码中工作,因为协程在调用loop.stop()后立即返回; if you added eg an await asyncio.sleep(1) after loop.stop() , you'd again get a (different) RuntimeError .如果你await asyncio.sleep(1)之后添加了例如await asyncio.sleep(1) loop.stop() ,你会再次得到一个(不同的) RuntimeError

To avoid such issues, I suggest that you migrate to the newer asyncio.run API and avoid both run_until_complete and stop .为避免此类问题,我建议您迁移到较新的asyncio.run API 并避免同时使用run_until_completestop Instead, you can just use an event to terminate the main function, and the loop with it:相反,您可以只使用一个事件来终止 main 函数,以及它的循环:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM