【问题标题】:asyncio: unable to create new event loopasyncio:无法创建新的事件循环
【发布时间】:2017-11-03 17:23:39
【问题描述】:

我在 Fedora 26 工作站上使用 Python 3.6.2。

下面是一些演示我的问题的剪贴簿代码:

编辑:将 Sam Hartman 的建议添加到代码中。

import asyncio, json
from autobahn.asyncio.websocket import WebSocketClientProtocol, WebSocketClientFactory

class MyClientProtocol(WebSocketClientProtocol):

    def onConnect(self, response):
        print(response.peer)

    def onOpen(self):
        print("open")
        self.sendMessage(json.dumps({'command': 'subscribe', 'channel': "1010"}).encode("utf8"))

    def onMessage(self, payload, isBinary):
        print("message")
        print(json.loads(payload))

factory1 = WebSocketClientFactory("wss://api2.poloniex.com:443")
factory1.protocol = MyClientProtocol
loop1 = asyncio.get_event_loop()
loop1.run_until_complete(loop1.create_connection(factory1, "api2.poloniex.com", 443, ssl=True))

try:
    loop1.run_forever()
except KeyboardInterrupt:
    pass
loop1.close()

asyncio.set_event_loop(asyncio.new_event_loop())

factory2 = WebSocketClientFactory("wss://api2.poloniex.com:443")
factory2.protocol = MyClientProtocol
loop2 = asyncio.get_event_loop()
loop2.run_until_complete(loop2.create_connection(factory2, "api2.poloniex.com", 443, ssl=True))

try:
    loop2.run_forever()
except KeyboardInterrupt:
    pass
loop2.close()

在关闭初始 asyncio 事件循环、创建另一个并将其设置为全局事件循环后,尝试使用新的事件循环会产生以下错误:

Fatal write error on socket transport
protocol: <asyncio.sslproto.SSLProtocol object at 0x7f8a84ed4748>
transport: <_SelectorSocketTransport fd=6>
Traceback (most recent call last):
  File "/usr/lib64/python3.6/asyncio/selector_events.py", line 762, in write
    n = self._sock.send(data)
OSError: [Errno 9] Bad file descriptor
Fatal error on SSL transport
protocol: <asyncio.sslproto.SSLProtocol object at 0x7f8a84ed4748>
transport: <_SelectorSocketTransport closing fd=6>
Traceback (most recent call last):
  File "/usr/lib64/python3.6/asyncio/selector_events.py", line 762, in write
    n = self._sock.send(data)
OSError: [Errno 9] Bad file descriptor

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.6/asyncio/sslproto.py", line 648, in _process_write_backlog
    self._transport.write(chunk)
  File "/usr/lib64/python3.6/asyncio/selector_events.py", line 766, in write
    self._fatal_error(exc, 'Fatal write error on socket transport')
  File "/usr/lib64/python3.6/asyncio/selector_events.py", line 646, in _fatal_error
    self._force_close(exc)
  File "/usr/lib64/python3.6/asyncio/selector_events.py", line 658, in _force_close
    self._loop.call_soon(self._call_connection_lost, exc)
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 574, in call_soon
    self._check_closed()
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 357, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Exception in callback _SelectorSocketTransport._read_ready()
handle: <Handle _SelectorSocketTransport._read_ready()>
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/txaio/_common.py", line 63, in call_later
    self._buckets[real_time][1].append(call)
KeyError: 412835000

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.6/asyncio/events.py", line 127, in _run
    self._callback(*self._args)
  File "/usr/lib64/python3.6/asyncio/selector_events.py", line 731, in _read_ready
    self._protocol.data_received(data)
  File "/usr/lib64/python3.6/asyncio/sslproto.py", line 503, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "/usr/lib64/python3.6/asyncio/sslproto.py", line 204, in feed_ssldata
    self._handshake_cb(None)
  File "/usr/lib64/python3.6/asyncio/sslproto.py", line 619, in _on_handshake_complete
    self._app_protocol.connection_made(self._app_transport)
  File "/usr/lib/python3.6/site-packages/autobahn/asyncio/websocket.py", line 97, in connection_made
    self._connectionMade()
  File "/usr/lib/python3.6/site-packages/autobahn/websocket/protocol.py", line 3340, in _connectionMade
    WebSocketProtocol._connectionMade(self)
  File "/usr/lib/python3.6/site-packages/autobahn/websocket/protocol.py", line 1055, in _connectionMade
    self.onOpenHandshakeTimeout,
  File "/usr/lib/python3.6/site-packages/txaio/_common.py", line 72, in call_later
    self._notify_bucket, real_time,
  File "/usr/lib/python3.6/site-packages/txaio/aio.py", line 382, in call_later
    return self._config.loop.call_later(delay, real_call)
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 543, in call_later
    timer = self.call_at(self.time() + delay, callback, *args)
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 553, in call_at
    self._check_closed()
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 357, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

在关闭之前的事件循环之后可能需要重新打开事件循环似乎是合理的。事实上,这个问题甚至显示了如何:Asyncio Event Loop is Closed

下面的代码应该可以实现这一点:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

所以我显然做错了什么。有人能看到缺少的东西吗?

【问题讨论】:

  • 您是否尝试过运行loop.stop() 而不是close()?
  • 事件循环在我调用 loop.close() 的地方没有运行,所以它是空操作。

标签: python python-asyncio autobahn


【解决方案1】:

我相当有信心您的工厂对象正在维护对旧事件循环的引用,大概是从asyncio.get_event_loop 获得的。 Asyncio 消费者不喜欢获取对循环的隐藏引用。

我的建议是闭环后重构web socket工厂

【讨论】:

  • 谢谢山姆。我尝试重建工厂,即使对第一个和第二个工厂/循环使用不同的变量名,但我仍然遇到相同的错误(OSError: [Errno 9] Bad file descriptor、RuntimeError: Event loop is closed、KeyError: 15068000)。就好像set_event_loop 调用根本不起作用。你认为我应该将此报告为错误吗?
  • 您可以在 get_event_loop 返回您设置的内容后检查 set_event_loop 是否正在使用断言。几乎可以肯定它在某处悬空引用,可能在您的 websocket 实现中
  • 好的。我会问 autobahn.asyncio 的人。谢谢山姆。
  • 上游错误报告,有兴趣的朋友:github.com/crossbario/autobahn-python/issues/925
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-09
  • 1970-01-01
  • 1970-01-01
  • 2023-01-08
  • 2017-02-01
相关资源
最近更新 更多