Python asyncio阻止协程,但不阻止websockets

时间:2019-12-02 17:46:38

标签: python python-asyncio

请考虑以下代码:

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

2 个答案:

答案 0 :(得分:0)

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)

答案 1 :(得分:0)

您的确切建议不起作用,因为create_task()抛出异常(正确),声称app_server不是协程。但是,根据您建议的代码,我已经能够使它像这样工作:

loop = asyncio.get_event_loop()
try:
    asyncio.ensure_future(app_server, loop=loop)
    print('1')
    loop.create_task(remote_data_retriever())
    print('2')
    loop.run_forever()
except Exception as e:
    print(e)