Python 生产者消费者模型是什么?
本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注!
作者| 慕课网精英讲师 朱广蔚
1. 简介
生产者和消费者问题是线程模型中的经典问题:
- 生产者和消费者共享同一个存储空间
- 生产者往存储空间中添加产品,消费者从存储空间中取走产品
- 当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞
Python 的内置模块 queue 提供了对生产者和消费者模型的支持,模块 queue 定义了类 Queue,类 Queue 表示一个被生产者和消费者共享的队列,类 Queue 提供如下常用方法:
| 方法 | 功能 |
| get() | 从队列中取走数据,如果队列为空,则阻塞 |
| put(item) | 向队列中放置数据,如果队列为慢,则阻塞 |
| join() | 如果队列不为空,则等待队列变为空 |
| task_done() | 消费者从队列中取走一项数据,当队列变为空时,唤醒调用 join() 的线程 |
2. 实现生产者消费者模型
创建生产者线程和消费者线程,使用一个共享队列连接这两个线程,代码如下:
import threading
import queueq = queue.Queue()
代码块1234
- 导入 threading 模块和 queue 模块
- 创建共享队列 q
def produce():for item in ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']:q.put(item)print('produce %s' % item)
代码块1234
- 创建生产者线程的入口函数 produce
- 生产者生产 8 个数据
- 调用 q.put(item) 将生产的数据放入到共享队列 q 中
def consume():for i in range(8):item = q.get()print(' consume %s' % item)
代码块1234
- 创建消费者线程的入口函数 consume
- 消费者消费 8 个数据
- 调用 q.get() 从共享队列 q 中取走数据
producer = threading.Thread(target=produce, args=())
consumer = threading.Thread(target=consume, args=())
producer.start()
consumer.start()
producer.join()
consumer.join()
代码块123456
- 创建生产者线程 producer,线程入口为 produce
- 创建消费者线程 consumer,线程入口为 consume
- 启动生产者线程和消费者线程,并等待它们结束
运行程序,输出结果如下:
produce a
produce bconsume a
produce cconsume bconsume c
produce dconsume d
produce econsume e
produce fconsume f
produce gconsume g
produce hconsume h
代码块12345678910111213141516
- 生产者生产了 8 个数据:a、b、c、d、e、f、g、h
- 消费者取走了 8 个数据:a、b、c、d、e、f、g、h
3. 实现生产者、计算者、消费者模型
创建生产者、计算者、消费者线程:
- 生产者生产 8 个数据
- 计算者对生产者输出的数据进行加工,将加工后的数据送往消费者
- 消费者取走计算者输出的数据
import threading
import queueq0 = queue.Queue()
q1 = queue.Queue()
代码块12345
- 导入模块 threading 和模块 queue
- 使用两个共享队列连接这三个线程共享队列 q0 连接生产者和计算者共享队列 q1 连接计算者和消费者
def produce():for item in ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']:q0.put(item)print('produce %s' % item)
代码块1234
- 创建生产者线程的入口函数 produce
- 生产者生产 8 个数据
- 调用 q0.put(item) 将生产的数据放入到共享队列 q0 中
def compute():for i in range(8):item = q0.get()item = item.upper() q1.put(item)
代码块12345
- 创建计算者线程的入口函数 compute
- 调用 q0.get() 读取生产者输出数据,并进行加工
- 调用 q1.put(item) 将加工后的数据放入到共享队列 q1 中
def consume():for i in range(8):item = q1.get()print(' consume %s' % item)
代码块1234
- 创建消费者线程的入口函数 consume
- 消费者消费 8 个数据
- 调用 q1.get() 从共享队列 q1 中取走数据
producer = threading.Thread(target=produce, args=())
computer = threading.Thread(target=compute, args=())
consumer = threading.Thread(target=consume, args=())
producer.start()
computer.start()
consumer.start()producer.join()
computer.join()
consumer.join()
代码块12345678910
- 创建生产者线程 producer,线程入口为 produce
- 创建计算者线程 computer,线程入口为 compute
- 创建消费者线程 consumer,线程入口为 consume
- 启动生产者线程、计算者线程、消费者线程,并等待它们结束
运行程序,输出结果如下:
produce a
produce b
produce cconsume A
produce d
produce econsume B
produce fconsume C
produce gconsume D
produce hconsume Econsume Fconsume Gconsume H
代码块12345678910111213141516
- 生产者生产了 8 个数据:a、b、c、d、e、f、g、h
- 计算者将数据加工为:A、B、C、D、E、F、G、H
- 消费者取走了 8 个数据:A、B、C、D、E、F、G、H
4. 同步生产者与消费者的推进速度
在生产者、消费者模型中,可能会存在两者推进速度不匹配的问题:生产者生产数据的速度较快,但是,消费者取走数据的速度较慢。
可以使用 queue 的 task_done() 方法和 join() 方法同步生产者与消费者的推进速度:
- 生产者调用 join() 方法,等待队列中所有的数据被取走
- 消费者调用 task_done() 方法,表示取走了队列中的一项数据,当队列为空时,唤醒阻塞在 join() 方法中的生产者
import threading
import queueq = queue.Queue()
代码块1234
- 导入 threading 模块和 queue 模块
- 创建共享队列 q
def produce():for item in ['A', 'B', 'C', 'D']:q.put(item)print('produce %s' % item)q.join()print('------------ q is empty')for item in ['E', 'F', 'G', 'H']:q.put(item) print('produce %s' % item)q.join() print('------------ q is empty')
代码块123456789101112
- 创建生产者线程的入口函数 produce
- 首先,生产 4 个数据:A、B、C、D调用 q.put(item) 将它们放入到队列 q 中调用 q.join() 等待消费者将它们全部取走
- 然后,生产 4 个数据:E、F、G、G调用 q.put(item) 将它们放入到队列 q 中调用 q.join() 等待消费者将它们全部取走
def consume():for i in range(8):item = q.get()print(' consume %s' % item)q.task_done()
代码块12345
- 创建消费者线程的入口函数 consume
- 调用 q.get() 从队列 q 中取走一个数据
- 调用 q.task_done(),表示已经从队列 q 中取走了一个数据,当队列为空时,唤醒生产者
producer = threading.Thread(target=produce, args=())
consumer = threading.Thread(target=consume, args=())
producer.start()
consumer.start()
代码块1234
- 创建生产者线程 producer,线程入口为 produce
- 创建消费者线程 consumer,线程入口为 consume
- 启动生产者线程和消费者线程,并等待它们结束
运行程序,输出结果如下:
produce A
produce Bconsume Aconsume B
produce Cconsume C
produce Dconsume D
------------ q is empty
produce Econsume E
produce Fconsume F
produce G
produce Hconsume Gconsume H
------------ q is empty
代码块123456789101112131415161718
- 生产者生产第一批数据 A、B、C、D,消费者将其取走
- 当第一批数据完全被消费者取走后,生产者才开始生产第二批数据
- 生产者生产第二批数据 E、F、G、H,消费者将其取走
欢迎关注「慕课网」,发现更多IT圈优质内容,分享干货知识,帮助你成为更好的程序员!
相关文章:
Python 生产者消费者模型是什么?
本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注! 作者| 慕课网精英讲师 朱广蔚 1. 简介 生产者和消费者问题是线程模型中的经典问题: 生产者和消费者共享同一个存储空间生产者往存储空间中添…...
手机银行评测系列:北京银行“京彩生活”7.0从用户视角出发,实现沉浸式体验重塑
易观:2023年3月28日,北京银行发布“京彩生活”APP 7.0版本,从旅程再造、特色金融、场景生态、平台联动、协同经营、体验管理和安全守护七大方面全面升级,从用户视角出发,重塑用户旅程,简化操作流程…...
ZJYC2023 浙江省大学生程序设计竞赛校内选拔赛部分题解 C J B L
ZJYC2023 浙江省大学生程序设计竞赛校内选拔赛部分题解 C J B L 难度分布: 签到:CJ Easy:BL Midium:IAGKFE Hard:DH 题解: 签到:CJ C - ^{-1} 参考代码: #include<bits/std…...
百科创建:7种有效的百科词条创建技巧
百科词条是互联网上最常见的知识信息资源之一,它们是人们查找信息的主要途径之一。创建一个高质量的百科词条并不是一件容易的事情,需要一些技巧和经验才能做到。下面是一些创建百科词条的技巧: 一、确保词条的独特性 在创建百科词条之前&…...
ThreeJS-dat.gui界面控制颜色、隐藏、位置(六)
下载组件dat.gui npm install dat.gui -S 引入组件 import * as dat from dat.gui //界面控制 代码: <template> <div id"three_div"> </div> </template> <script> import * as THREE from "three"; import {O…...
接口自动化测试,完整入门篇
目录 1. 什么是接口测试2. 基本流程3. 需求分析4. 用例设计5. 脚本开发6. 结果分析7. 完整脚本8. 参考资料1. 什么是接口测试 顾名思义,接口测试是对系统或组件之间的接口进行测试,主要是校验数据的交换,传递和控制管理过程,以及…...
利用ControlNet重新定义你的AI姿势
利用ControlNet重新定义你的AI姿势 前段时间给大家分享了如何利用colab实现AI绘画自由,现在Stable Diffusion WebUI Colab TW又更新了不少新功能。最重要的是可以通过谷歌硬盘的快捷方式导入模型,极大的节省了谷歌硬盘容量。 众所周知,谷歌…...
中医药NER命名实体识别基于SPANNER方式
一个不知名大学生,江湖人称菜狗 original author: Jacky Li Email : 3435673055qq.com Time of completion:2023.3.5 Last edited: 2023.3.5 导读 本文使用SPANNER方式实现对中医药进行实体识别,采用focal loss 进行优化。 本文章作用防止安静…...
Vue必掌握
目录 一、组件通信方式 二、v-if和v-for 三、生命周期 1、描述 2、setup和created谁先执行 3、setup中为什么没有beforeCreate和created 四、双向绑定 v-model 1、定义 2、本质,原理 3、好处 五、如何扩展一个组件 1、mixins 缺点 2、slot插槽 3、e…...
SSM部分
声明式事务 从之前的事务控制的代码中可以看出,是有规律可循,代码的结构基本是确定的,所以框架就可以将固定模式的代码抽取出来,进行相关的封装。 封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作。 …...
【Springboot系列】Springboot接管所有Controller,magic-api源码阅读
系列文章地址:Spring Boot学习大纲,可以留言自己想了解的技术点 最近在项目中使用了一个第三方的包 magic-api,节省了很多的时间,整体来说就是只用写sql就好了,不用写service,controller那些,全部统一处理了。 具体的使用大家可以搜索下,网上到处都是,建议去官网看。…...
二、LED子系统数据结构详解
个人主页:董哥聊技术我是董哥,嵌入式领域新星创作者创作理念:专注分享高质量嵌入式文章,让大家读有所得!文章目录1、核心数据结构1.1 gpio_led_platform_data1.2 gpio_leds_priv1.3 gpio_led1.4 gpio_led_data1.5 led_…...
Kubernetes(11):数据存储详解
在前面已经提到,容器的生命周期可能很短,会被频繁地创建和销毁。那么容器在销毁时,保存在容器中的数据也会被清除。这种结果对用户来说,在某些情况下是不乐意看到的。为了持久化保存容器的数据,kubernetes引入了Volume的概念。 Volume是Pod中能够被多个容器访问的共享目录…...
随想录Day43--动态规划: 1049. 最后一块石头的重量 II , 494. 目标和 , 474.一和零
最后一块石头重量转化为将一个集合分隔成两个集合,两个集合之间的差值最小,就是最后剩下最小的石头重量。这里可以求集合的一个平均值,如果正好等于平均值,说明可以抵消,这时候重量为0,如果不行,…...
Qt中对TCP粘包的处理
当时用TCP协议传输数据时,经常出现粘包的现象 当服务器向客户端发送数据之后,客户端还没有接收数据的时候,这段时间数据在什么地方? 1、服务器?服务器已经发出数据了 2、网线?数据应该在内存,怎…...
贪心-单调递增的数字
当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时,我们称这个整数是单调递增的。 给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。 示例 1: 输入: n 10 输出: 9示例 2: 输入: n 1234 输出: 1234示例 3: 输入…...
你真的会用搜索引擎吗?
作为一名在校大学生,对于搜索资料这一件事深有体会,特别是在期末考试突击的时候,如何利用搜索引擎,快速找到自己想要的知识,快速理解这个知识点,想必是每位大学生的必备技能了。 我们在学习一个知识点的过…...
KDCJ-20kV冲击耐压测试仪
一、产品简介 KDCJ-20kV冲击耐压测试仪是电力设备高压试验的基本项目之一,电力设备在设计、制造及修缮之后都要求进行冲击试验以验证或检验。因此,冲击电压试验设备有着广泛的应用,在工厂、研究机构及大专院校的高压试验室中都可以看到不同规…...
【Mybatis源码分析】TypeAliasRegistry源码分析
TypeAliasRegistry源码分析一、引入类型别名二、typeAlias 的三种配置方式三、TypeAliasRegistry源码分析三种配置方式源码解析校验过程Mybatis默认的别名配置四、总结一、引入类型别名 当配置 XML 文件,需要指明Java类型时,类型别名可替代Java类型的全…...
节点高负载
如何判断节点高负载? 可以通过 top 或 uptime 来确定 load 大小,如果 load 小于 CPU 数量,属于低负载,如果大于 CPU 数量 2~3 倍,就比较高了,当然也看业务敏感程度,不太敏感的大于 4 倍算高负载。 排查思路 观察监控:通常不是因为内核 bug 导致的高负载,在卡死之前…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学
一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件,其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时,价带电子受激发跃迁至导带,形成电子-空穴对,导致材料电导率显著提升。…...
Unity基础-Mathf相关
Unity基础-Mathf相关 一、Mathf数学工具 概述 Mathf是Unity中封装好用于数学计算的工具结构体,提供了丰富的数学计算方法,特别适用于游戏开发场景。它是Unity开发中最常用的数学工具之一,能够帮助我们处理各种数学计算和插值运算。 Mathf…...
Python网页自动化测试,DrissonPage库入门说明文档
🛰️ 基本逻辑 操作浏览器的基本逻辑如下: 创建浏览器对象,用于启动或接管浏览器获取一个 Tab 对象使用 Tab 对象访问网址使用 Tab 对象获取标签页内需要的元素对象使用元素对象进行交互 除此以外,还能执行更为复杂的操作&am…...
