对于asyncio的队列,使用get()时就已经把队列中的元素弹出了,而task_done()只是减少未完成任务数量。 这是我找到的相关资料(虽然是线程的队列,但协程的应该也同理): https://stackoverflow.com/questions/1593299/python-queue-get-task-done-issue/1593330#1593330
No, queue.get() pops the item off the queue. After you do that, you can do whatever you want with it, as long as the producer works like it should and doesn’t touch it anymore. queue.task_done() is called only to notify the queue that you are done with something (it doesn’t even know about the specific item, it just counts unfinished items in the queue), so that queue.join() knows the work is finished.
之后,我实践了一下。
>>> import asyncio
>>> queue=asyncio.Queue(5)
>>> async def sb():
while 1:
await queue.put(1)
print(queue)
>>> async def cnm():
while 1:
await queue.get()
print(queue)
queue.task_done()
print(queue)
>>> async def main():
task=asyncio.create_task(sb())
await asyncio.sleep(5)
task.cancel()
asyncio.create_task(cnm())
>>> asyncio.run(main())
<Queue maxsize=5 _queue=[1] tasks=1>
<Queue maxsize=5 _queue=[1, 1] tasks=2>
<Queue maxsize=5 _queue=[1, 1, 1] tasks=3>
<Queue maxsize=5 _queue=[1, 1, 1, 1] tasks=4>
<Queue maxsize=5 _queue=[1, 1, 1, 1, 1] tasks=5>
<Queue maxsize=5 _queue=[1, 1, 1, 1] tasks=5>
<Queue maxsize=5 _queue=[1, 1, 1, 1] tasks=4>
<Queue maxsize=5 _queue=[1, 1, 1] tasks=4>
<Queue maxsize=5 _queue=[1, 1, 1] tasks=3>
<Queue maxsize=5 _queue=[1, 1] tasks=3>
<Queue maxsize=5 _queue=[1, 1] tasks=2>
<Queue maxsize=5 _queue=[1] tasks=2>
<Queue maxsize=5 _queue=[1] tasks=1>
<Queue maxsize=5 tasks=1>
<Queue maxsize=5>
可以看到,使用get()后,队列中的元素减少了,但是tasks没有减少,使用task_done()后tasks才减少。 查看queue的属性: 猜测_unfinished_tasks是上面的tasks。 验证:
>>> async def cnm():
while 1:
await queue.get()
print(queue._unfinished_tasks)
queue.task_done()
print(queue._unfinished_tasks)
>>> asyncio.run(main())
<Queue maxsize=5 _queue=[1] tasks=1>
<Queue maxsize=5 _queue=[1, 1] tasks=2>
<Queue maxsize=5 _queue=[1, 1, 1] tasks=3>
<Queue maxsize=5 _queue=[1, 1, 1, 1] tasks=4>
<Queue maxsize=5 _queue=[1, 1, 1, 1, 1] tasks=5>
5
4
4
3
3
2
2
1
1
0
猜测正确。 因此,如果不从队列中取出值而直接用task_done()的话会使队列中还有元素,但是未完成的任务数量为0。
>>> queue.put_nowait(2)
>>> queue
<Queue at 0x24cf9965610 maxsize=5 _queue=[2] tasks=1>
>>> queue.task_done()
>>> queue
<Queue at 0x24cf9965610 maxsize=5 _queue=[2]>
|