优先选collections.deque用于单线程场景,因其O(1)两端操作、无锁高效;多线程协调必须用queue.Queue,它提供阻塞、超时及线程安全保证。

用 queue.Queue 还是 collections.deque?看场景
不是“哪个更好”,而是“谁更合适”。queue.Queue 是为多线程安全设计的阻塞队列,collections.deque 是纯数据结构,快但不自带线程保护。如果你在单线程里做缓存、滑动窗口或简单 FIFO,直接用 deque;只要涉及 threading 或需要 put_nowait()/get_nowait() 之外的阻塞行为(比如等生产者放数据),就必须选 queue.Queue。
queue.Queue 的阻塞和超时容易被当“默认行为”误用
很多人一写 q.get() 就卡死,因为没意识到它默认无限等待。这不是 bug,是设计——它本就用来协调线程节奏。但新手常把它当普通容器用,结果主线程挂住。
- 加
timeout=1可避免死等,超时抛queue.Empty,记得try/except -
q.put(item, block=False)和q.put_nowait(item)效果一样,但后者更直白 - 别在非多线程场景用
queue.Queue:它内部有锁和条件变量,单线程下纯属性能拖累
collections.deque 的 append/pop 性能优势在哪
deque 在两端增删是 O(1),而 list.append() 虽然也是 O(1),但 list.pop(0) 是 O(n) —— 因为要移动所有后续元素。这对高频出队(比如消息循环、日志缓冲)影响明显。
- 常用操作:
d = deque([1,2,3]); d.append(4); d.popleft() - 别用
d[0]或d[-1]做频繁访问:虽然合法,但不如专门变量存着快 -
maxlen参数很有用:deque(maxlen=100)自动丢老数据,适合滚动日志或采样
多线程里混用 deque 会静默出错
没有报错,但数据可能丢失或错乱。Python 的 GIL 不保证 deque.append() + deque.popleft() 组合的原子性。两个线程同时操作同一个 deque,哪怕只是各干各的,也可能让内部指针错位。
立即学习“Python免费学习笔记(深入)”;
- 实测中,10 万次并发增删后
len(d)常不等于预期值 - 想“轻量级线程安全”,不要自己加
threading.Lock包一层——那还不如直接用queue.Queue - 如果真要极致性能+线程安全,得换方案:比如用
asyncio.Queue(协程)、或分片deque+ 消息队列中转
真正难的是判断“到底需不需要线程安全”。很多所谓“并发”其实只是 I/O 等待,用 asyncio + deque 更干净。别一看到“多任务”就 reflexively 上 queue.Queue。











