首页 > 解决方案 > 协程上的 Python asyncio 块,但不是 websockets

问题描述

考虑以下代码:

async def remote_data_retriever():
    remote = Remote(sock_path)
    while True:
        Cached.update_global(remote.get_global())
        await asyncio.sleep(RTR_RETR_INTERVAL)


async def on_message(websocket, path):
    async for message in websocket:
        data = Cached.get_global()
        await websocket.send(json.dumps(data.__dict__))


if __name__ == '__main__':
    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    ssl_context.load_cert_chain(RTR_CERT_PATH)
    app_server = websockets.serve(on_message, RTR_LISTEN_HOST, RTR_LISTEN_PORT, ssl=ssl_context)
    try:
        asyncio.get_event_loop().run_until_complete(app_server)
        print('1')
        asyncio.get_event_loop().run_until_complete(remote_data_retriever())
        print('2')
        asyncio.get_event_loop().run_forever()
    except Exception as e:
        print(e)

此代码将打印“1”,然后从不打印“2”。如何正确安排协程,使其不会阻塞以下调用

asyncio.get_event_loop().run_until_complete(remote_data_retriever())

?

标签: pythonpython-asyncio

解决方案


run_until_complete(task)立即开始任务并等待其真正结束,而不是await. 但是您的第二个任务使用while True永无止境。

您应该将任务添加到循环使用create_task(task)并稍后使用run_forever().

asyncio.get_event_loop().create_task(app_server)
print('1')
asyncio.get_event_loop().create_task(remote_data_retriever())
print('2')
asyncio.get_event_loop().run_forever()

然后这两个任务将在一个循环中运行,await并将停止一个任务以启动另一个任务。


每个人都可以运行的示例代码

import asyncio

async def task_1():
    number = 0
    while True:
        number += 1
        print('task1', number)
        await asyncio.sleep(1)

async def task_2():
    number = 0
    while True:
        number += 1
        print('task2', number)
        await asyncio.sleep(1)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    try:
        loop.create_task(task_1())
        print('1')
        loop.create_task(task_2())
        print('2')
        loop.run_forever()
    except Exception as e:
        print(e)

推荐阅读