Python 四种队列实现原理与性能对比:deque、Queue 及多进程队列
本文深入解析 Python 中四种队列实现机制。重点对比 collections.deque 与 list 在时间复杂度上的差异,阐述其线程安全特性。同时分析 queue.Queue、asyncio.Queue 及 multiprocessing.Queue 在多线程、协程及多进程场景下的适用性、阻塞机制与底层实现差异,帮助开发者根据场景选择最优队列方案。
Python 队列基础与 deque 原理
队列作为线性表的一种,其核心定义是限制插入操作仅能在表尾进行,而删除操作仅能在表头执行。
查阅 Python 官方文档可知,标准库提供了四种队列实现:queue.Queue、asyncio.Queue、multiprocessing.Queue 以及 collections.deque。
collections.deque
deque 全称为 double-ended queue(双端队列),因其支持两端操作,既可模拟栈(Stack)也可模拟队列(Queue)。
deque 提供了丰富的操作方法,具体函数列表参见下图:

与基于 list 实现的队列相比,deque 在时间与空间复杂度上更具优势。list 在执行出队(pop)或插入(insert)时,因元素移动导致空间复杂度约为 O(n);而 deque 在执行出队(pop)和入队(append)时,时间复杂度稳定为 O(1)。
deque 同样支持 in 操作符进行成员检查,示例代码如下:
q = collections.deque([1, 2, 3, 4]) print(5 in q) # False print(1 in q) # True
此外,deque 封装了 rotate 方法,支持顺时针与逆时针旋转操作。
# 顺时针 q = collections.deque([1, 2, 3, 4]) q.rotate(1) print(q) # [4, 1, 2, 3] q.rotate(1) print(q) # [3, 4, 1, 2]
# 逆时针 q = collections.deque([1, 2, 3, 4]) q.rotate(-1) print(q) # [2, 3, 4, 1] q.rotate(-1) print(q) # [3, 4, 1, 2]
关于线程安全性,通过审查 collections.deque 中 append()、pop() 等方法的源码可知,这些操作均为原子操作,因此在 GIL(全局解释器锁)的保护下,deque 是线程安全的。
static PyObject * deque_append(dequeobject *deque, PyObject *item) { Py_INCREF(item); if (deque_append_internal(deque, item, deque->maxlen) < 0) return NULL; Py_RETURN_NONE; }
使用 dis 模块分析字节码可见,append 操作对应单行字节码,确认为原子操作。

综上所述,collections.deque 是一种便于实现队列的数据结构,具备线程安全特性且拥有高性能表现。
多线程与协程队列对比
queue.Queue & asyncio.Queue
queue.Queue 与 asyncio.Queue 均支持多生产者与多消费者模式,且底层均基于 collections.deque 构建。二者均提供 Queue(FIFO)、PriorityQueue(优先级)及 LifoQueue(LIFO)三种接口,API 设计保持一致。
主要区别在于应用场景:queue.Queue 适用于多线程环境,而 asyncio.Queue 专为协程通信设计。受 asyncio 机制影响,queue.Queue 中的阻塞接口在 asyncio.Queue 中转化为返回协程对象的形式。具体差异对比见下表:
| queue.Queue | asyncio.Queue | |
|---|---|---|
| 介绍 | 同步队列 | asyncio队列 |
| 线程安全 | 是 | 否 |
| 超时机制 | 通过timeout参数实现 | 通过asyncio.wait_for()方法实现 |
| qsize() | 预估的队列长度(获取qsize到下一个操作之间,queue有可能被其它的线程修改,导致qsize大小发生变化) | 准确的队列长度(由于是单线程,所以queue不会被其它线程修改) |
| put() / set() | put(item, block=True, timeout=None),可以通过设置block是否为True来配置put和set方法是否为阻塞,并且可以为阻塞操作设置最大时长timeout,block为False时行为和put_nowait()方法一致。 | put()方法会返回一个协程对象,所以没有block参数和timeout参数,如果需要非阻塞方法,可以使用put_nowait(),如果需要对阻塞方法应用超时,可以使用coroutine asyncio.wait_for()。 |
多进程队列实现机制
multiprocessing.Queue
multiprocessing 模块提供了三种队列类型:Queue、SimpleQueue 以及 JoinableQueue。

multiprocessing.Queue 兼具线程安全与进程安全特性,可视为 queue.Queue 的多进程版本。其功能与 threading.Queue 类似,支持 put 和 get 操作,底层结构基于 multiprocessing.Pipe。
尽管 multiprocessing.Queue 底层基于 Pipe,但数据传递并非直接写入 Pipe,而是先写入进程本地 buffer,再由 feeder 线程写入底层 Pipe。这种设计旨在实现超时控制与非阻塞 put/get。因此,Queue 提供了 join_thread、cancel_join_thread 及 close 函数以控制 feeder 行为:close 用于关闭 feeder 线程,join_thread 用于等待 feeder 线程结束,cancel_join_thread 则用于控制进程退出时是否自动 join feeder 线程。若使用 cancel_join_thread,可能导致部分数据未被写入 Pipe 从而引发数据丢失。
与 threading.Queue 不同,multiprocessing.Queue 默认不支持 join() 和 task_done 操作,需使用 mp.JoinableQueue 对象方可启用这些功能。
SimpleQueue 是一种简化版队列,去除了 Queue 中的 buffer 机制,避免了相关潜在问题,但其 put 和 get 方法均为阻塞式且不支持超时控制。
四种队列方案总结
总结
通过对比可见,上述四种结构虽均实现队列功能,但侧重点各异:collections.deque 在数据结构层面实现队列,属于基础数据结构,无特定应用场景支持;queue 模块面向多生产/消费线程;asyncio.queue 模块面向多生产/消费协程;而 multiprocessing.queue 模块则面向多生产/消费进程。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









