Python Queue对象中qsize()与unfinished_tasks的差异及差异场景
我发现调用Python Queue对象的qsize()方法与查看unfinished_tasks属性时得到的值不同,请问在哪些场景下二者的结果会存在较大差异?
相关代码示例:
from queue import Queue dbjobs = Queue() ... ... ... print("qsize() = " + str(dbjobs.qsize())) print("unfinished_tasks = " + str(dbjobs.unfinished_tasks))
示例结果1:
qsize() = 0 unfinished_tasks = 79
示例结果2:
qsize() = 2 unfinished_tasks = 117
核心逻辑先理清
先明确两个值的本质:
qsize():返回队列中尚未被消费者取出的待处理任务数量unfinished_tasks:统计的是已被消费者取出,但未调用task_done()标记完成的任务数(每次调用get()取任务时自动+1,调用task_done()时自动-1)
常见差异场景
任务已取出但未完成/未标记
这是最典型的场景。比如多线程消费队列时,线程用get()取出任务后开始执行,但还没执行完,也没触发task_done()。此时qsize()因任务被取走而减少,unfinished_tasks却持续增加,直到task_done()执行才会回落。示例结果1就是这种情况:队列里的任务已全被取走,但所有取出的任务都还在执行中(或没标记完成),所以qsize()为0,unfinished_tasks等于已取出未完成的任务数79。部分任务完成未标记
如果消费者取出多个任务后,只给其中一部分调用了task_done(),会直接拉大二者的差值。比如示例结果2:队列里还剩2个待处理任务,加上已经被取走但未标记完成的115个任务,最终unfinished_tasks显示为117。异常导致
task_done()未执行
如果消费者处理任务时抛出异常,导致task_done()的代码没被执行到(比如try块逻辑崩溃、except未覆盖到对应异常),这些已取出的任务会一直留在unfinished_tasks的计数里,而qsize()已经因为任务被取走而减少,二者的差异会持续存在,直到程序重启。手动修改
unfinished_tasks属性
虽然unfinished_tasks是Queue的内部属性,但如果代码里直接手动修改它的值(比如dbjobs.unfinished_tasks = 100),会直接破坏计数逻辑,导致和qsize()的结果完全脱节,出现无规律的差异。这种操作强烈不推荐。
内容的提问来源于stack exchange,提问作者AaronC

