在正常关闭时取消它们时,我遇到了几个预定的asyncio.futures(被安排为服务器的消息编写器)的问题。 每个活动客户端连接都有一个活动编写器会话。
writer = asyncio.gather(
*[self._dispatchMessage(message, c) for c in connections],
loop=self.loop,
return_exceptions=True
)
每个作家未来(GatheringFuture)都存储在活动会话列表中......
connection.sessions = set()
...作家未来一旦完成就会被删除。这是通过添加" done_callback"走向未来。
writer.add_done_callback(lambda task: connection.sessions.remove(task))
connection.sessions.add(writer)
一旦我优雅地关闭了我的服务器,我就会遍历活动连接及其会话并取消(future.cancel())它们不会以未来的作家未来结束。
async def cancel_sessions(connection):
for s in connection.sessions:
s.cancel()
asyncio.wait(
[await cancel_sessions(c) for c in client_connections],
timeout=None
)
这样可行,但是只要我有更多的连接,我就会不断获得asyncio循环异常,尽管几乎无处不在地调试异常以进行调试。对我来说,看起来,问题是由" done_callbacks"添加到作家期货(GatheringFuture)。似乎我必须删除call_backs,否则我最终得到:
Traceback (most recent call last):
File "uvloop/cbhandles.pyx", line 49, in uvloop.loop.Handle._run
File "...server.py", line 353, in <lambda>
writer.add_done_callback(lambda task: connection.sessions.remove(task))
myUtilsAsyncLoopException: Async exception "<_GatheringFuture finished result=[None, None]>"
如果我从代码中省略这一行......
writer.add_done_callback(lambda task: connection.sessions.remove(task))
......我没有遇到问题。我现在的问题是如何处理取消的asyncio.futures上的done_callbacks。我的印象是,在取消之前,我不必手动删除未来的回调。但似乎在用回调取消未来时,这些回调可能会在相关未来被取消时抛出异常。
我还不明白为什么只有当我有超过2个连接时才会发生这种情况,因为我认为处理它们没有太大区别。
答案 0 :(得分:0)
我想我自己解决了。通常有助于在问题中制定问题以更好地理解情况。我的问题似乎与asyncio无关,而是一个简单的逻辑问题。所有connection.sessions都有相同的(编写者)未来,实际上asyncio.future“done_callbacks”仍然在取消时被调用,但是将相同的future(writer)添加到几个connection.sessions会导致lambda回调中的一个关键错误。
答案 1 :(得分:0)
对于阅读这个问题的每个人:问题源于注册&#34;完成回调&#34;每个可用连接的未来。这发生在for循环中,但回调从未在未来完成时绑定到实际连接,而是绑定到for循环的最后一个连接。因此总是相同的连接对象。
文档建议使用functools将某些值绑定到未来的回调。这最终起作用(将for循环中的值绑定到回调中)并且没有&#34;有趣&#34;副作用。