异步函数中的变量未在 while-True 循环中重新计算
Variable in Async function not re-evaluated in while-True loop
我制作了一个虚拟服务器来测试我的 websockets 应用程序。它侦听 subscription
消息,然后通过套接字提供有关这些订阅的信息。
class' 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 循环不包含 "context switching point",这意味着 asyncio
事件循环基本上挂在那里,永远执行 阻塞 while 循环。
添加await sleep()
打破魔法阵;甚至 await sleep(0)
也能提供帮助。
聪明的代码可能应该将 asyncio.Condition
与 self.subscriptions
结合使用,但这超出了您最初问题的范围。
我制作了一个虚拟服务器来测试我的 websockets 应用程序。它侦听 subscription
消息,然后通过套接字提供有关这些订阅的信息。
class' 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 循环不包含 "context switching point",这意味着 asyncio
事件循环基本上挂在那里,永远执行 阻塞 while 循环。
添加await sleep()
打破魔法阵;甚至 await sleep(0)
也能提供帮助。
聪明的代码可能应该将 asyncio.Condition
与 self.subscriptions
结合使用,但这超出了您最初问题的范围。