Asyncio.run 给出 RuntimeError 循环已关闭

Asyncio.run gives RuntimeError loop is closed

当尝试创建具有异步功能的简单 coap 服务器时,asyncio.run 它 return 事件循环已关闭。代码如下:

import aiocoap
import aiocoap.resource as resource


class CoAPServer(resource.Resource):
    def __init__(self) -> None:
        super().__init__()

    async def render_get(self, request):
        print("Received GET request ...")
        return aiocoap.Message(code=aiocoap.GET, payload="hello friend".encode('utf8'))

    async def render_post(self, request):
        print("Received POST request ...")
        return aiocoap.Message(code=aiocoap.CHANGED, payload="that's me".encode('utf8'))

async def main():
    root = resource.Site()
    root.add_resource(['demo'], CoAPServer)
    task = asyncio.create_task(aiocoap.Context.create_server_context(root, bind=('127.0.0.1', 5683)))
    await task

if __name__ == "__main__":
    asyncio.run(main())

出现此错误:

Exception ignored in: <function RecvmsgSelectorDatagramTransport.__del__ at 0x7f9a04c57310>
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/aiocoap/util/asyncio/recvmsg.py", line 95, in __del__
    self.close()
  File "/usr/local/lib/python3.8/dist-packages/aiocoap/util/asyncio/recvmsg.py", line 83, in close
    self._loop.call_soon(self._protocol.connection_lost, None)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 719, in call_soon
    self._check_closed()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 508, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

相反,如果我使用 get_event_loop().run_forever(),根据文档

不推荐使用

Application developers should typically use the high-level asyncio functions, such as asyncio.run(), and should rarely need to reference the loop object or call its methods. This section is intended mostly for authors of lower-level code, libraries, and frameworks, who need finer control over the event loop behavior.

if __name__ == "__main__":
    asyncio.get_event_loop().run_forever()

有效。当前在 wsl

中使用 python3.8.10

这个问题是由于 aiocoap 仍在使用(并且在某些地方使用得很糟糕)习语来支持 Python 3.7 或(在废弃的部分中)甚至更早的版本。

我知道 asyncio.run() 是首选,但在下一个 aiocoap 版本发布之前(我也计划在其中更新示例),旧的习惯用法在支持的范围内最有效 Python 版本。

asyncio.run(main())的代码在Unix系统上运行良好。因此,这很可能是 aiocoap 如何处理 WSL 环境中的事件循环的问题。现在,在维护人员修补库之前,您最好使用 asyncio.get_event_loop().run_forever()