2022年1月3日 Python asyncio.Queue的get()和task_done()

对于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的属性:
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]>
`queue.Queue()`是Python中的标准队列类,它可以用来实现队列的基本操作,如入队和出队等。`task_done()`是Queue类中的一个方法,用于通知队列,一个线程已经完成了它的任务,可以从队列中移除任务。 在使用队列时,当一个线程完成它的任务后,应该调用`task_done()`方法来通知队列。这样,队列就可以知道哪些任务已经完成,哪些任务还在等待处理。当队列中的所有任务都被标记为完成时,队列会解除阻塞状态,以便程序可以继续执行下一步操作。 下面是一个使用`queue.Queue()`和`task_done()`的示例代码: ```python import queue import threading def worker(q): while True: item = q.get() # 处理任务 print(f"Processing item: {item}") # 标记任务完成 q.task_done() q = queue.Queue() # 创建多个线程 for i in range(5): t = threading.Thread(target=worker, args=(q,)) t.daemon = True t.start() # 添加任务到队列 for item in range(10): q.put(item) # 等待队列中的任务完成 q.join() print("All tasks are done.") ``` 在这个示例中,我们创建了一个队列`q`,并启动了5个线程来处理队列中的任务。我们将10个任务添加到队列中,并使用`q.join()`等待队列中的所有任务完成。在每个线程中,我们使用`q.get()`获取队列中的任务,并在处理完任务后使用`q.task_done()`标记任务完成。最后,当所有任务都完成时,程序会输出"All tasks are done."。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值