在Python多线程开发中,多个线程同时修改同一个普通列表或字典时,很容易出现数据不一致的问题,而queue模块内置的几种队列类型天生支持线程安全,不需要开发者手动加锁就能在多线程环境下稳定使用,是线程间通信和任务调度的常用工具。

queue模块核心队列类型
queue模块提供了三种常用的队列类型,分别对应不同的使用场景:
- Queue:先进先出队列,最常用的类型,先加入队列的元素会先被取出
- LifoQueue:后进先出队列,和栈的结构一致,最后加入的元素会先被取出
- PriorityQueue:优先级队列,元素会按照优先级排序,优先级高的元素先被取出
基础队列操作示例
以最常用的先进先出Queue为例,核心操作包括入队、出队、判断队列状态等,下面是基础用法示例:
import queue
import threading
import time
# 创建最大容量为5的先进先出队列
q = queue.Queue(maxsize=5)
# 入队操作
q.put("任务1")
q.put("任务2")
q.put(100)
print(f"当前队列元素数量:{q.qsize()}")
print(f"队列是否为空:{q.empty()}")
print(f"队列是否已满:{q.full()}")
# 出队操作
item1 = q.get()
item2 = q.get()
print(f"取出的元素:{item1}, {item2}")
# 任务完成标记,配合task_done使用
q.task_done()
多线程场景实战:生产者消费者模型
queue模块最常见的应用场景就是实现生产者消费者模型,生产者线程往队列里放任务,消费者线程从队列里取任务处理,队列自动处理线程间的同步问题,下面是完整示例:
import queue
import threading
import time
import random
# 创建队列,不限制最大容量
task_queue = queue.Queue()
# 生产者函数,生成任务放入队列
def producer(name):
for i in range(3):
task = f"{name}生产的任务{i}"
task_queue.put(task)
print(f"生产者{name}放入任务:{task}")
time.sleep(random.randint(1, 2))
# 放入结束标记
task_queue.put(None)
# 消费者函数,从队列取任务处理
def consumer(name):
while True:
task = task_queue.get()
# 遇到结束标记就退出
if task is None:
# 把结束标记重新放回队列,让其他消费者也能收到
task_queue.put(None)
break
print(f"消费者{name}处理任务:{task}")
time.sleep(random.randint(1, 3))
# 标记任务处理完成
task_queue.task_done()
if __name__ == "__main__":
# 创建1个生产者线程和2个消费者线程
p = threading.Thread(target=producer, args=("P1",))
c1 = threading.Thread(target=consumer, args=("C1",))
c2 = threading.Thread(target=consumer, args=("C2",))
p.start()
c1.start()
c2.start()
# 等待所有任务处理完成
task_queue.join()
print("所有任务处理完成")
不同队列类型的使用差异
LifoQueue后进先出队列
后进先出队列的使用方式和Queue基本一致,只是出队顺序相反,适合需要栈结构的场景:
import queue
lifo_q = queue.LifoQueue()
lifo_q.put("A")
lifo_q.put("B")
lifo_q.put("C")
print(lifo_q.get()) # 输出C
print(lifo_q.get()) # 输出B
print(lifo_q.get()) # 输出A
PriorityQueue优先级队列
优先级队列的元素需要是可比较的,通常可以用元组(优先级, 数据)的形式传入,优先级数值越小优先级越高:
import queue pri_q = queue.PriorityQueue() # 优先级为1的任务 pri_q.put((1, "高优先级任务")) # 优先级为3的任务 pri_q.put((3, "低优先级任务")) # 优先级为2的任务 pri_q.put((2, "中优先级任务")) print(pri_q.get()) # 输出(1, '高优先级任务') print(pri_q.get()) # 输出(2, '中优先级任务') print(pri_q.get()) # 输出(3, '低优先级任务')
使用注意事项
- put和get方法默认是阻塞的,队列满时put会阻塞,队列空时get会阻塞,如果不想阻塞可以设置block=False参数,此时队列满或空会抛出queue.Full或queue.Empty异常
- 使用get方法取出元素后,如果不需要配合join等待所有任务完成,可以不调用task_done方法
- 队列的maxsize参数如果不设置或者设置为负数,代表队列容量没有限制
- 不要在多线程场景下对普通列表使用append、pop等操作来实现队列功能,普通列表不是线程安全的,很容易出现数据错误
queue模块的队列仅支持线程安全,不支持进程间安全,如果是多进程场景需要使用multiprocessing模块提供的队列类型。
除了基础的入队出队操作,queue模块还支持超时设置,比如put(item, timeout=2)代表最多等待2秒入队,超时则抛出异常,开发者可以根据实际需求选择合适的参数配置。