asyncio.Queue卡住了1个协程添加到队列,1个协程从队列中获取

在我下面的简单 asyncio 代码中,应用程序有一个任务self.add_item_loop_task不断地向asyncio.Queuenamed 中添加一个整数self.queue,而第二个任务则self.get_item_loop_task不断地等待将某些内容添加到队列中并将print其退出。

但是,这个应用程序0在我运行时只打印一次,然后卡在那里。我相信循环self.get_item_loop_task没有继续。为什么会这样?

import asyncio

class App:
    def __init__(self):
        self.queue = asyncio.Queue()

    async def start(self):
        self.add_item_loop_task = asyncio.create_task(self.add_item_loop())
        self.get_item_loop_task = asyncio.create_task(self.get_item_loop())
        await asyncio.wait(
            [
                self.add_item_loop_task,
                self.get_item_loop_task,
            ]
        )

    async def stop(self):
        self.add_item_loop_task.cancel()
        self.get_item_loop_task.cancel()

    async def add_item_loop(self):
        i = 0
        while True:
            await self.queue.put(i)
            i += 1
            await asyncio.sleep(1)

    async def get_item_loop(self):
        while True:
            item = await self.queue.get()
            print(item)


app = App()
try:
    asyncio.run(app.start())
except KeyboardInterrupt:
    asyncio.run(app.stop())

回答

这是由 asyncio 的一些可疑实现细节引起的。当您说 self.queue = asyncio.Queue()这实际上会创建一个事件循环(如果尚不存在)。同时,当你调用asyncio.run()它时,它总是会创建一个新的事件循环。这意味着如果你在调用之前创建一个队列,你asyncio.run()会得到一些奇怪的行为,因为有两个事件循环,一个是你的队列使用的,一个是asyncio.run正在使用的。

您可以通过将 的创建移动App到您传入的协程函数中来解决此问题,asyncio.run()如下所示。这样做您的应用程序按预期工作。

async def main():
    app = App()
    await app.start()

asyncio.run(main())


以上是asyncio.Queue卡住了1个协程添加到队列,1个协程从队列中获取的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>