因为queue.PriorityQueue底层依赖heapq,而heapq要求元素可比较(即支持<运算符),字典类型不可比较,导致TypeError。

为什么直接往 queue.PriorityQueue 里放字典会报错?
因为 queue.PriorityQueue 底层依赖 heapq,而 heapq 要求元素可比较(即支持 运算)。字典、列表、集合等无序类型在 Python 3 中默认不可比较,一放进去就会抛出 <code>TypeError: '。
常见错误写法:
import queue
q = queue.PriorityQueue()
q.put({'priority': 1, 'task': 'A'}) # ❌ 报错解决思路:必须确保入队对象本身支持比较。最稳妥的方式是封装成自定义类,或用元组(靠第一个元素排序)。
用元组作为优先级载体时,priority 放前面还是后面?
必须把优先级数值放在元组最左侧。Python 元组比较是逐元素进行的,只有第一个元素相同时才比第二个,依此类推。否则低优先级任务可能被高优先级“压住”。
立即学习“Python免费学习笔记(深入)”;
正确做法:
-
q.put((1, 'task_A'))→ 优先级 1 最高 -
q.put((5, 'task_B'))→ 优先级 5 较低 - 如果想让数字越小优先级越低,就用负数:
(-5, ...)或直接反转逻辑
注意:如果多个任务优先级相同(如都为 2),Python 会继续比较第二个元素。若第二个元素不可比较(比如又是字典),仍会报错。所以建议加个唯一序号防冲突:
import itertools counter = itertools.count() # 生成递增整数 q.put((priority, next(counter), task_data))
queue.PriorityQueue 的 get() 是阻塞还是非阻塞?
默认阻塞。调用 q.get() 时若队列为空,线程会一直等待,直到有新元素入队。这在多线程协作中很常用,但也容易卡死——比如生产者已结束但忘了发“结束信号”,消费者就永远 hang 住。
安全用法:
- 加超时:
q.get(timeout=1),超时抛queue.Empty,需捕获 - 非阻塞:
q.get_nowait(),空时直接抛queue.Empty - 配合
q.task_done()和q.join()实现任务完成同步(尤其在工作线程中)
别漏掉 task_done():每处理完一个 get() 出来的项,必须调用它,否则 join() 永远不会返回。
和 heapq 直接操作比,queue.PriorityQueue 多了什么?
核心就一点:queue.PriorityQueue 是线程安全的,所有操作(put、get、qsize 等)都自带锁;而原生 heapq 只是堆操作工具函数,不保证并发安全。
所以:
- 单线程、追求性能 → 直接用
heapq(更轻量,无锁开销) - 多线程、需要跨线程协调 → 必须用
queue.PriorityQueue -
queue.PriorityQueue不提供heapify或批量初始化接口,不能像heapq.heapify(list)那样从已有数据快速建堆
真正容易被忽略的是:它的线程安全只覆盖了队列本身的读写,不保护你存进去的业务对象。比如你 put 了一个可变对象(如 dict),多个线程 get 到后并发修改它,依然要自己加锁或深拷贝。


















