如何使用asyncio.wait_for到run_until_complete同步调用Python中的async方法

How to use asyncio.wait_for to run_until_complete to synchronously call async method in Python

为了允许通过 Python websocket 接收数据超时,FAQ: How do I set a timeout on recv()? 建议使用异步接收数据:

await asyncio.wait_for(websocket.recv(), timeout=10)

由于我接收数据的功能不是异步的,我已经将 调整为 运行 asyncio 循环直到接收到数据或超时发生:

loop.run_until_complete(asyncio.wait_for(ws.recv(), timeout=10))

不幸的是,此声明似乎无效,因为发生了以下异常:

An asyncio.Future, a coroutine or an awaitable is required

对我来说,asyncio.wait_for 似乎不是 run_until_complete 的有效参数,尽管 documentation 清楚地显示了一个 await 的示例。

我在这里遗漏了什么 - 在同步方法中使用 asyncio.wait_for 的正确方法是什么?

您需要 loop.run_until_complete 使用协程。为此,您可以将接收代码包装到一个异步函数中:

async def receive_message():
    return await asyncio.wait_for(ws.recv(), timeout=10)

loop.run_until_complete(receive_message())

这是一个完整的工作代码:

import asyncio
import websockets

URI = "ws://0.0.0.0:8765"
TIMEOUT = 2

async def create_ws():
    return await websockets.connect(URI)

async def receive_message():
    ws = await create_ws()
    print("Connected")
    message = await asyncio.wait_for(ws.recv(), timeout=TIMEOUT)
    print(f"Received message in less than {TIMEOUT} seconds: {message}")

if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(receive_message())

Python 中有两个常用的 websocket 模块可用。 而 websockets is imported with import websockets there is also the websocket-client 是用 import websocket.

导入的

两个模块提供几乎相同的 API 其中 ws.recv() 允许接收数据。

模块彼此如此相似的事实可能会引起混淆,这至少会导致我的例外。

虽然 websockets 能够进行异步操作,但 websocket 不能。这意味着我的声明

loop.run_until_complete(asyncio.wait_for(ws.recv(), timeout=10))

将仅适用于 websockets,如果与 websocket 一起使用,例外情况

An asyncio.Future, a coroutine or an awaitable is required

会发生。