我制作了一个虚拟服务器来测试我的 websockets 应用程序。它监听订阅
消息,然后通过套接字提供有关这些订阅的信息。
类的 subscriptions
属性在初始化时为空,并且应该在 listen()
函数接收订阅消息时填充。然而,似乎 talk()
中的 self.subscriptions
从未被附加到,让它陷入无限的 while 循环并且永远不会传输消息。
通过在 for 循环之后添加一行 await asyncio.sleep(1)
解决了这个问题。但为什么? self.subscriptions
难道不应该在每次 for 循环开始时重新求值吗?
代码如下:
class DummyServer:
def __init__(self):
self.subscriptions = []
def start(self):
return websockets.serve(self.handle, 'localhost', 8765)
async def handle(self, websocket, path):
self.ws = websocket
listen_task = asyncio.ensure_future(self.listen())
talk_task = asyncio.ensure_future(self.talk())
done, pending = await asyncio.wait(
[listen_task, talk_task],
return_when=asyncio.FIRST_COMPLETED
)
for task in pending:
task.cancel()
async def listen(self):
while True:
try:
msg = await self.ws.recv()
msg = json.loads(msg)
await self.triage(msg) # handles subscriptions
except Exception as e:
await self.close()
break
async def talk(self):
while True:
for s in self.subscriptions:
dummy_data = {
'product_id': s
}
try:
await self.send(json.dumps(dummy_data))
except Exception as e:
await self.close()
break
await asyncio.sleep(1) # without this line, no message is ever sent
最佳答案
在您的函数开始时,subscriptions
为空,for
主体未被评估。因此,您的协程实际上与:
async def talk(self):
while True:
pass
while 循环不包含“上下文切换点”,这意味着 asyncio
事件循环基本上卡在那里,永远执行阻塞 while 循环。
添加 await sleep()
打破魔圈;甚至 await sleep(0)
也有帮助。
聪明的代码可能应该将 asyncio.Condition
与 self.subscriptions
结合使用,但这超出了您最初问题的范围。
关于python - 异步函数中的变量未在 while-True 循环中重新计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50746986/