python - 异步函数中的变量未在 while-True 循环中重新评估
问题描述
我制作了一个虚拟服务器来测试我的 websockets 应用程序。它侦听subscription
消息,然后通过套接字提供有关这些订阅的信息。
类的subscriptions
属性在初始化时是空的,应该在listen()
函数接收订阅消息时填满。但是,似乎self.subscriptions
intalk()
从未附加到,使其陷入无限的 while 循环并且从不传输消息。
await asyncio.sleep(1)
通过在 for 循环后添加一行来解决问题。但为什么?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
,但这超出了您原始问题的范围。
推荐阅读
- ios - 将两个同名的类添加到同一工作区下的多个xcodeproject
- django - 管理站点显示时区错误
- java - Axon MongoDB - message='E11000 重复键错误集合 uniqueAggregateIndex dup key: { : "101", : 0 }
- sql-server - 即使在声明标量变量后我也收到此错误“必须声明标量变量“@col_shipping_price”
- c++ - 在 [a,b] 区间之间找到相同的数字
- sphinx - 狮身人面像错误: (type='index') 已经存在
- mariadb - MariaDB 为每个 find_in_set 值选择记录
- matrix - 如何使用颤振执行有关缩放,旋转和平移使用矩阵的功能
- c - 在使用诸如 C 之类的编程语言的某些软件中是否有间接寻址的实际应用?
- numpy - 如何根据值标记 numpy 数组?