python - 异步函数中的变量未在 while-True 循环中重新计算

标签 python websocket python-asyncio

我制作了一个虚拟服务器来测试我的 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.Conditionself.subscriptions 结合使用,但这超出了您最初问题的范围。

关于python - 异步函数中的变量未在 while-True 循环中重新计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50746986/

相关文章:

php - 共享主机上的 Websockets : not possible because of shared hosting itself or because of non-php integrations?

python - 类似 Python 2.7 + Bottle 框架的 socket.io

python - 使异步事件循环响应 Windows(和 Unix)上的 KeyboardInterrupt

python - asyncio create_task 永远运行

python - 两个列表(男孩和女孩)的所有可能(一夫一妻制)配对

python - 错误 : command 'i686-linux-gnu-gcc' failed with exit status 1 while installing pylibbvg

javascript - 将不同数据类型的类型化数组合并到单个数组缓冲区中

python - 可以或如何在 Google Cloud Functions 上使用 Python asyncio?

Python:使用嵌套类时出现 NameError

python - pydantic 与 mypy 的使用