当前位置:首页>python>python生产者与消费者模型

python生产者与消费者模型

  • 2026-09-03 20:11:23
python生产者与消费者模型
公司楼下的包子铺做出来的包子越来越难吃了,每次吃包子都很纠结,为了讨好自己的嘴和胃,不得已早上开始自己做点吃的,煮一个鸡蛋和蒸几个小馒头吃起来也挺舒服。
包子还是怀念之前在家老爸,老妈做的包子。包子蒸出来之后那种香味扑鼻而来,也不顾着烫手直接拿出来咬上一口,反正心是乐开花的,嘴是咧咧歪歪的。咽下去的第一口不是韭菜或鸡蛋的味道,而是舌头尖上传来的酥麻。后面再来几口时那个面和韭菜鸡蛋混在一起的那个香呀...除了包子,还有幺爹家做的韭菜盒子,每次他家做韭菜盒子我都是闻着香味来的,然后呢必须得吃上一个才能满足。
儿时包子和韭菜盒子的味道在外面可能永远吃不上了。在家呢?或许还能吃到,不过很难,原因无非就是现在的人都变懒了嘛,能用钱买到就不会下那个力气了。赶哪天在家得闲向老爸学学,学会之后亲自做上一回。等学会这个手艺之后也好解馋呀。
说完包子,接下来咱说说python中的生产者与消费者模型。示例都是AI生成的,不过很通俗易懂。很巧也是一个做包子和吃包子的示例。那就开始吧!
想象一个包子铺的场景:
  • 生产者:做包子的师傅
  • 消费者:吃包子的顾客
  • 缓存区:放包子的蒸笼

PART 01

基础概念
1. 同步问题
如果只有1个蒸笼位置:
* 师傅做好包子,但蒸笼满了 → 师傅要等(阻塞)
* 顾客想吃包子,但蒸笼空了 → 顾客要等(阻塞)
2. 为什么要用这个模型?
* 解耦:师傅只管做,顾客只管吃
* 平衡速度:师傅做得快时可以存一些,顾客来的时候直接吃

PART 02

简单示例
import threadingimport timeimport queue# 创建一个蒸笼(最多放5个包子)basket = queue.Queue(maxsize=5)# 生产者:做包子的师傅def producer(name):    count = 1    while True:        print(f"{name} 开始做第 {count} 个包子...")        time.sleep(1)  # 做包子需要时间        # 如果蒸笼满了,这里会等待        basket.put(f"包子{count}")        print(f"{name} 做好了第 {count} 个包子,蒸笼里还有 {basket.qsize()} 个")        count += 1# 消费者:吃包子的顾客def consumer(name):    while True:        time.sleep(1.5)  # 顾客消化时间        # 如果蒸笼空了,这里会等待        baozi = basket.get()        print(f"{name} 吃了 {baozi},蒸笼里还剩 {basket.qsize()} 个")        # 告诉队列这个包子处理完了        basket.task_done()# 创建角色并开始if __name__ == "__main__":    # 2个师傅做包子    threading.Thread(target=producer, args=("张师傅",), daemon=True).start()    threading.Thread(target=producer, args=("李师傅",), daemon=True).start()    # 3个顾客吃包子    threading.Thread(target=consumer, args=("小王",), daemon=True).start()    threading.Thread(target=consumer, args=("小赵",), daemon=True).start()    threading.Thread(target=consumer, args=("小孙",), daemon=True).start()    # 让程序运行一会    time.sleep(10)    print("\n包子铺打烊了!")
输出示例:
text
张师傅 开始做第 1 个包子...李师傅 开始做第 1 个包子...张师傅 做好了第 1 个包子,蒸笼里还有 1 个李师傅 做好了第 1 个包子,蒸笼里还有 2 个小王 吃了 包子1,蒸笼里还剩 1 个张师傅 开始做第 2 个包子...小赵 吃了 包子2,蒸笼里还剩 0 个...
现实生活中的类比
编程概念
包子铺例子
实际场景
生产者
做包子师傅
数据采集程序
消费者
吃包子顾客
数据分析程序
缓冲区
放包子蒸笼
消息队列
Queue
蒸笼规则
线程安全的数据结构

PART 03

更实用的例子:下载和处理图片
import threadingimport queueimport timeimport random# 消息队列task_queue = queue.Queue(maxsize=10)result_queue = queue.Queue()# 生产者:模拟下载图片def downloader(name):    for i in range(1, 6):        print(f"{name} 开始下载图片{i}...")        time.sleep(random.uniform(0.5, 1.5))  # 模拟下载时间        # 下载完成,放入任务队列        task_queue.put(f"图片{i}_数据")        print(f"{name} 下载完成图片{i},待处理队列长度:{task_queue.qsize()}")# 消费者:模拟处理图片def processor(name):    while True:        # 从队列获取任务        image_data = task_queue.get()        print(f"{name} 开始处理 {image_data}...")        time.sleep(random.uniform(1, 2))  # 模拟处理时间        # 处理完成        result = f"{image_data}_已处理"        result_queue.put(result)        print(f"{name} 处理完成,结果:{result}")        # 标记任务完成        task_queue.task_done()# 主程序if __name__ == "__main__":    print("=== 图片处理系统开始工作 ===")    # 启动2个下载者(生产者)    for i in range(2):        t = threading.Thread(target=downloader, args=(f"下载器{i+1}",))        t.start()    # 启动3个处理器(消费者)    for i in range(3):        t = threading.Thread(target=processor, args=(f"处理器{i+1}",), daemon=True)        t.start()    # 等待所有下载任务完成    time.sleep(8)    # 等待所有任务被处理    task_queue.join()    print("\n=== 所有任务处理完成 ===")    print(f"处理结果数量:{result_queue.qsize()}")

PART 04

关键点总结
  1. Queue的作用:
    * 线程安全,不需要自己加锁
    * 自动处理等待(满时阻塞生产者,空时阻塞消费者)
  2. 核心方法:
    * put():放入数据(生产者用)
    * get():取出数据(消费者用)
    * task_done():标记任务完成
    * join():等待所有任务完成
  3. 适用场景:
    * 爬虫:生产者抓取网页,消费者解析内容
    * 日志处理:生产者写日志,消费者分析日志
    * 数据处理:生产者读取数据,消费者计算统计

PART 05

简单记忆口诀
生产放,消费取
队列满,生产等
队列空,消费等
用Queue,锁省心
生产者与消费者模型,软件测试中很少使用,多用于研发主要是后台业务。而另一个使用场景较多的就是爬虫了,如有感兴趣,可以再次基础上深入。

最新文章

随机文章