Python队列:生产者消费者模式
线程安全队列(Queue)用于解决多线程开发中的
数据共享与同步
的问题
1.为什么使用队列
正确使用queue.Queue,可以构建出高性能的多线程程序,既充分利用多核优势,又避免复杂的锁管理问题。
多个线程同时访问共享资源
时,队列通过内置锁机制提供线程安全的数据交换方式解决了以下问题
- 线程间的安全通信
- 数据一致性问题
- 生产消费速率不匹配
2.队列的生命周期
生命周期:
- 创建队列
- 生产者 put 任务
- 消费者 get 任务
- 处理任务
- 调用task_done(确认任务完成)
- 队列join解除
3.队列各个阶段详解
启动阶段
- queue.Queue()创建队列容器
- queue.put() 添加任务到队列
# 创建线程安全队列
# maxsize限制队列长度
task_queue = queue.Queue(maxsize=100)
# 启动生产者阶段
producer_thread = threading.Thread(
target=producer,
args=(max_page,)
)
producer_thread.start()
#等待生产完成
producer_thread.join()
# 启动消费者阶段
consumers = []
for i in range(NUM_CONSUMERS):
t = threading.Thread(
target=consumer,
args=(i + 1,)
)
t.start()
consumers.append(t)
任务生产阶段
- queue.get() 从队列取任务
- None 标记任务完成
def producer(max_page):
logger.info("生产者开始生产{}个任务",max_page)
for page in range(max_page):
url = f"https://example/page/{page}"
task_queue.put(url)
for _ in range(NUM_CONSUMERS):
task_queue.put(None)
logger.success("[生产者] 任务完成,已发送结束信号")
任务消费阶段
- queue.qsize() 返回队列的大小
- queue.task_done() 标记任务完成
def consumer(worker_id):
while True:
task = task_queue.get()
try:
if task is None:
task_queue.task_done()
break
time.sleep(2)
logger.success(f"[消费者{worker_id}] 请求成功|url:{task}| 队列剩余: {task_queue.qsize()}")
task_queue.task_done()
except Exception as e:
logger.debug(f"{task}[消费者{worker_id}] 出现异常: {str(e)}")
task_queue.task_done()
终止阶段
- task_queue.join() 等待任务完成
task_queue.join()
logger.success("所有任务处理完毕")
其他方法
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False,Queue.full 与 maxsize 大小对应
4.完整示例代码
import queue
import time
from loguru import logger
import threading
NUM_CONSUMERS = 50
# 创建线程安全队列
task_queue = queue.Queue()
def producer(max_page):
logger.info("生产者开始生产{}个任务",max_page)
for page in range(max_page):
url = f"https://example/page/{page}"
task_queue.put(url)
for _ in range(NUM_CONSUMERS):
task_queue.put(None)
logger.success("[生产者] 任务完成,已发送结束信号")
def consumer(worker_id):
while True:
task = task_queue.get()
try:
if task is None:
task_queue.task_done()
break
time.sleep(2)
logger.success(f"[消费者{worker_id}] 请求成功|url:{task}| 队列剩余: {task_queue.qsize()}")
task_queue.task_done()
except Exception as e:
logger.debug(f"{task}[消费者{worker_id}] 出现异常: {str(e)}")
task_queue.task_done()
if __name__ == '__main__':
max_page = 5
producer_thread = threading.Thread(
target=producer,
args=(max_page,)
)
producer_thread.start()
producer_thread.join()
consumers = []
for i in range(NUM_CONSUMERS):
t = threading.Thread(
target=consumer,
args=(i + 1,)
)
t.start()
consumers.append(t)
task_queue.join()
logger.success("所有任务处理完毕")