我做了一个虚拟服务器来测试我的websockets应用程序。它侦听subscription
消息,然后通过套接字提供有关这些订阅的信息。
类'subscriptions
属性在初始化时为空,应该填充为listen()
函数接收订阅消息。但是,好像self.subscriptions
中的talk()
似乎永远不会附加到其中,而是留在无限的while循环中,永远不会传输消息。
通过在for循环之后添加一行await asyncio.sleep(1)
来解决问题。但为什么?每次启动for循环时,是否不应重新评估self.subscriptions
?
以下代码:
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
答案 0 :(得分:3)
在您的函数开始时,subscriptions
为空,并且不评估for
正文。因此,您的协程几乎与以下内容相同:
async def talk(self):
while True:
pass
while循环不包含"上下文切换点",这意味着asyncio
事件循环基本上挂起,永远执行阻塞 while循环。
添加await sleep()
打破了魔术圈;即使await sleep(0)
也可以提供帮助。
聪明的代码可能应该将asyncio.Condition
与self.subscriptions
结合使用,但这个问题超出了原始问题的范围。