Python queue模块使用教程

Python queue 模块使用教程

目录

  1. queue模块概述
  2. 基础队列类型
  3. 核心方法
  4. 队列阻塞与超时
  5. 队列大小控制
  6. 多线程安全特性
  7. 高级使用技巧
  8. 常见问题
  9. 性能优化
  10. 注意事项

1. queue模块概述

Python的queue模块提供了线程安全的队列实现,主要用于多线程编程环境中安全地传递消息或数据。它是Python标准库的一部分,无需额外安装。

主要特点:

  • 线程安全:所有方法都是原子操作
  • 阻塞操作:支持阻塞式put/get
  • 超时控制:可以设置操作超时时间
  • 大小限制:可以限制队列容量

2. 基础队列类型

Queue (FIFO队列)

基本先进先出队列:

import queue

q = queue.Queue(maxsize=5)  # 创建容量为5的队列

# 基本操作
q.put('item1')
q.put('item2')
print(q.get())  # 输出: item1
print(q.get())  # 输出: item2

LifoQueue (LIFO队列/栈)

后进先出队列(栈结构):

import queue

lq = queue.LifoQueue()

lq.put('first')
lq.put('second')
print(lq.get())  # 输出: second (后进先出)
print(lq.get())  # 输出: first

PriorityQueue (优先级队列)

按优先级顺序取出的队列:

import queue

pq = queue.PriorityQueue()

pq.put((3, 'Low priority'))
pq.put((1, 'High priority'))
pq.put((2, 'Medium priority'))

print(pq.get()[1])  # 输出: High priority
print(pq.get()[1])  # 输出: Medium priority
print(pq.get()[1])  # 输出: Low priority

SimpleQueue (简单的FIFO队列)

无界的 FIFO 队列构造函数。简单的队列,缺少任务跟踪等高级功能。这个特殊实现为小功能在交换中提供额外的保障。

3. 核心方法

put() 方法

向队列中添加项目:

q.put(item, block=True, timeout=None)

参数:

  • block: 当队列满时是否阻塞(默认True)
  • timeout: 阻塞超时时间(秒)

示例:

try:
    q.put('item', block=True, timeout=2)  # 最多等待2秒
except queue.Full:
    print("队列已满,无法添加")

get() 方法

从队列中获取并移除项目:

item = q.get(block=True, timeout=None)

参数同put()方法。

示例:

try:
    item = q.get(block=True, timeout=3)  # 最多等待3秒
except queue.Empty:
    print("队列为空,无法获取")

其他关键方法

  1. qsize() - 返回队列的近似大小

    print(q.qsize())  # 注意:在多线程环境中不精确
    
  2. empty() - 判断队列是否为空

    if not q.empty():
        item = q.get()
    
  3. full() - 判断队列是否已满

    if not q.full():
        q.put(item)
    
  4. task_done() - 标记任务完成

    q.get()
    # 处理任务...
    q.task_done()  # 告诉队列任务处理完成
    
  5. join() - 阻塞直到所有任务完成

    q.join()  # 阻塞直到所有任务被处理并标记为done
    

4. 队列阻塞与超时

队列操作默认是阻塞的,但可以控制:

# 非阻塞put
try:
    q.put(item, block=False)  # 立即返回,如果队列满则抛出queue.Full
except queue.Full:
    print("队列已满")

# 非阻塞get
try:
    item = q.get(block=False)  # 立即返回,如果队列空则抛出queue.Empty
except queue.Empty:
    print("队列为空")

# 带超时的操作
try:
    q.put(item, timeout=2.5)  # 最多等待2.5秒
    item = q.get(timeout=1.0)  # 最多等待1秒
except queue.Full:
    print("放入超时")
except queue.Empty:
    print("获取超时")

5. 队列大小控制

创建队列时可以设置最大容量:

q = queue.Queue(maxsize=100)  # 最多容纳100个元素
  • maxsize=0(默认):无限容量
  • maxsize>0:有限容量,put可能阻塞
  • maxsize<0:等同于0,无限容量

6. 多线程安全特性

queue模块的所有实现都是线程安全的:

import threading
import queue

def worker(q):
    while True:
        item = q.get()
        print(f"处理: {item}")
        q.task_done()

q = queue.Queue()
threads = []
for i in range(3):
    t = threading.Thread(target=worker, args=(q,))
    t.daemon = True
    t.start()
    threads.append(t)

for item in range(10):
    q.put(item)

q.join()  # 等待所有任务完成

7. 高级使用技巧

自定义优先级规则

import queue

class CustomPriorityQueue(queue.PriorityQueue):
    def _put(self, item):
        # 自定义优先级逻辑
        priority = -item[0]  # 反转优先级
        super()._put((priority, item[1]))

pq = CustomPriorityQueue()
pq.put((3, 'Low'))
pq.put((1, 'High'))
pq.put((2, 'Medium'))

print(pq.get()[1])  # 输出: Low (因为优先级被反转)

队列任务跟踪

q = queue.Queue()

def monitored_put(item):
    print(f"准备放入: {item}")
    q.put(item)
    print(f"已放入: {item}, 队列大小: {q.qsize()}")

def monitored_get():
    print(f"尝试获取, 队列大小: {q.qsize()}")
    item = q.get()
    print(f"已获取: {item}, 队列大小: {q.qsize()}")
    return item

生产者-消费者模式

import queue
import threading
import random
import time

def producer(q, id):
    for i in range(5):
        item = f"产品-{id}-{i}"
        q.put(item)
        print(f"生产者 {id} 生产了 {item}")
        time.sleep(random.random())

def consumer(q, id):
    while True:
        item = q.get()
        if item is None:  # 终止信号
            break
        print(f"消费者 {id} 消费了 {item}")
        q.task_done()
        time.sleep(random.random() * 2)

q = queue.Queue()
producers = [threading.Thread(target=producer, args=(q, i)) for i in range(3)]
consumers = [threading.Thread(target=consumer, args=(q, i)) for i in range(2)]

for t in producers + consumers:
    t.start()

for t in producers:
    t.join()

# 发送终止信号
for _ in consumers:
    q.put(None)

for t in consumers:
    t.join()

8. 常见问题

问题1:队列卡死

现象:程序卡在put()get()操作上

解决方案:

  • 设置合理的超时时间
  • 确保所有线程最终都会处理队列
  • 使用qsize()监控队列状态

问题2:任务未正确标记完成

现象:join()永远阻塞

解决方案:

  • 确保每个get()后都有对应的task_done()
  • 使用try-finally确保标记:
item = q.get()
try:
    # 处理item
finally:
    q.task_done()

问题3:优先级队列排序错误

现象:元素未按预期顺序取出

解决方案:

  • 确保优先级是可比较的
  • 对于复杂对象,实现__lt__方法或使用元组(priority, data)

9. 性能优化

  1. 合理设置队列大小

    • 太大消耗内存
    • 太小容易阻塞
  2. 批量操作

    • 合并小任务为大任务减少队列操作
  3. 避免频繁查询

    • 减少empty()/full()调用,直接使用try-catch
  4. 选择合适的队列类型

    • 默认FIFO满足大多数场景
    • 特殊需求选择LIFO或PriorityQueue
  5. 线程池配合

    • 结合concurrent.futures.ThreadPoolExecutor使用

10. 注意事项

  1. 资源清理

    • 确保所有线程都能正确退出
    • 使用哨兵值(如None)通知消费者线程退出
  2. 错误处理

    • 总是处理queue.Fullqueue.Empty异常
    • 记录队列操作失败的情况
  3. 监控队列

    • 记录队列大小变化
    • 监控任务处理时间
  4. 合理设计

    • 生产者速率应与消费者处理能力匹配
    • 考虑使用多个队列分离不同优先级任务
  5. 测试策略

    • 模拟队列满/空的情况
    • 测试多线程竞争条件
  6. 替代方案

    • 对于简单场景,考虑使用collections.deque
    • 对于跨进程通信,使用multiprocessing.Queue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值