asyncio.Queue 卡在 1 个协程添加到队列中,1 个协程从队列中获取
asyncio.Queue Stuck With 1 Coroutine Adding to Queue, 1 Coroutine Getting from Queue
在我下面的简单 asyncio 代码中,应用程序有一个任务 self.add_item_loop_task
不断地向名为 self.queue
的 asyncio.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 代码中,应用程序有一个任务 self.add_item_loop_task
不断地向名为 self.queue
的 asyncio.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())