首页 > 解决方案 > 在 asyncio.wait 中捕获异常

问题描述

我有一个应用程序通过 websocket 连接从 Python 服务器获取消息。如果客户端在两者之间断开连接,服务器将无法发送消息。我想利用这一点并在发生这种情况时引发异常,以便正确清理而不会出现很多错误。

async def status(websocket, message):
    try:
        print("\nDEBUG: "+message)
        await asyncio.wait([websocket.send(message)])
    except:
        raise Abort()

当客户端断开连接时,此函数会引发错误。

DEBUG: Waiting for sale to start
Task exception was never retrieved
future: <Task finished name='Task-79' coro=<WebSocketCommonProtocol.send() done, defined at C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py:521> exception=ConnectionClosedError('code = 1006 (connection closed abnormally [internal]), no reason')>
Traceback (most recent call last):
  File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py", line 827, in transfer_data
   message = await self.read_message()
  File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py", line 895, in read_message
   frame = await self.read_data_frame(max_size=self.max_size)
  File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py", line 971, in read_data_frame
   frame = await self.read_frame(max_size)
  File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py", line 1047, in read_frame
   frame = await Frame.read(
  File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\framing.py", line 105, in read
   data = await reader(2)
  File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\asyncio\streams.py", line 721, in readexactly
   raise exceptions.IncompleteReadError(incomplete, n)
asyncio.exceptions.IncompleteReadError: 0 bytes read on a total of 2 expected bytes

现在,我知道这是由于文档asyncio中提到的异常处理不当造成的,但我无法编写适当的方法来处理异常。我确实尝试复制此答案并使其正常工作。但是它根本不发送任何消息。令人惊讶的是,根本没有错误消息。这是我复制粘贴后的代码handler

async def status(websocket, message):
    print("\nDEBUG: "+message)
    done, pending = await asyncio.wait([websocket.send(message)])
    assert not pending
    future, = done
    if future.exception() is websockets.ConnectionClosedError:
        raise Abort()

我也尝试剥离asyncio.wait()并使用简单websocket.send(),但这不适用于这个应用程序。我对 Python 没有经验,Future因此将不胜感激。从技术上讲,我可能heartbeats每次都可以用来检查连接是否有效,但这可能会消耗更多的网络,所以我不想这样做。

标签: pythonpython-3.xwebsocketpython-asyncio

解决方案


如果您只在等待一个协程,请直接执行,异常会自然传播:

try
    print("\nDEBUG: "+message)
    await websocket.send(message)
except Exception:
    raise Abort()

没有理由使用asyncio.wait旨在等待多个任务的。将它用于一个协程会产生大量开销:一个新任务被创建、调度、运行并最终在一个元素集中返回,并且必须在单独的步骤中检查其结果。这基本上就是最后一个代码片段所做的。


没有 的简单websocket.send(message)(当用 定义时async defawait实际上什么都不做。从技术上讲,它从协程函数创建一个 couroutine 对象,但该 couroutine 没有被执行。


推荐阅读