生产者与消费者模式--课后程序(Python程序开发案例教程-黑马程序员编著-第13章-课后作业)
创始人
2025-05-28 02:25:55

实例1:生产者与消费者模式

生产者与消费者模式是多线程同步应用的经典案例,它通过一个固定大小的缓冲区解决了代表“生产者”和代表“消费者”的两个线程在实际运行时发生的强耦合问题——由于生产者的生产能力与消费者的消费能力互不匹配,导致双方必须互相阻塞等待处理。在生产者与消费者模式中,生产者与消费者彼此之间通过缓冲区进行通讯,示意过程如图1所示。

 

  1. 线程同步示例

由图1可知,生产者在生产完数据之后直接将数据存储到队列中,无需等待消费者处理;消费者直接从队列中取出数据,无需再等待生产者生产,平衡了生产者与消费者的能力。

假设现在有一群生产者(Producer)和一群消费者(Consumer)通过一个市场来交互产品。生产者的“策略”是若市场上剩余的产品少于1000个则生产100个产品放到市场上;而消费者的“策略”是若市场上剩余产品的数量多于100个则消费3个产品。

现在请使用Queue类编写一个案例,模拟以上描述的生产者与消费者模式的场景。

实例目标

  1. 熟练地自定义线程
  2. 掌握Queue类的使用,会使用队列实现线程同步

实例分析

按照实例描述,我们可将生产者与消费者视为两个线程,它们的要求如下:

  1. 生产者线程:若队列数据长度小于1000,则调用put()方法向队列中写入数据。
  2. 消费者线程:若队列中数据的长度大于100,则调用get()方法从队列取出数据。

按照如上要求需要自定义两个线程类Producer和Consumer。为了更真实地模拟生产者与消费者的场景,这里分别创建两个生产者和5个消费者。

代码实现

(1)导入Queue类,创建一个队列对象,具体代码如下。

from  queue import Queue

queue = Queue()                            # 创建队列对象

(2)定义一个代表生产者的线程类Producer。在Producer类中重写父类的run()方法, 该方法中首先设置初始的产品数量为0,然后判断队列大小是否比1000大,若大于1000则不做任何操作,否则就开始向队列中添加数据,最后让线程休眠一秒钟降低其执行效率,具体代码如下。

import threading

import time

class Producer(threading.Thread):      # 代表生产者的线程

    def run(self):

        global queue

        count = 0                           # 初始的产品数量

        while True:

            for i in range(100):

                if queue.qsize() > 1000: # 若队列的大小比1000大,不做任何操作

                     pass

                else:

                     count += 1

                     message = '生成产品' + str(count)

                     queue.put(message)    # 把新生产的产品放到队列

                     print(message)

            time.sleep(1)

(3)定义一个代表消费者的线程类Consumer。在Consumer类中重写父类的run()方法,该方法中首先判断队列中数据的大小是否小于100,若小于100则不做任何操作,否则就开始从队列中取出数据,然后让线程休眠一秒钟降低其执行效率,具体代码如下。

class Consumer(threading.Thread):       # 代表消费者的线程

    def run(self):

        global queue

        while True:

            for i in range(3):

                if queue.qsize() < 100:   # 若队列的大小比100小,不做任何操作

                    pass

                else:

                    # 从队列中销售产品

                    message = self.name + '消费了 ' + queue.get()

                    print(message)

            time.sleep(1)

(4)分别创建两个代表生产者的线程和5个代表消费者的线程,并向队列中添加500个产品,具体代码如下。

if __name__ == '__main__':

    for i in range(500):

        queue.put('初始产品' + str(i))    # 往队列中放入初始产品500个

    for i in range(2):

        producer = Producer()

        producer.start()

    for i in range(5):

        consumer = Consumer()

        consumer.start()

代码测试

运行程序,控制台不停地打印如下信息:

生成产品95

生成产品96

生成产品97

生成产品98

生成产品99

生成产品100

Thread-3消费了 初始产品15

Thread-3消费了 初始产品16

Thread-3消费了 初始产品17

Thread-4消费了 初始产品18

Thread-4消费了 初始产品19

Thread-4消费了 初始产品20

生成产品101

生成产品102

生成产品103

生成产品104

生成产品105

相关内容

热门资讯

Java发起同步和异步HTTP... 同步与异步概念辨析 同步(synchronous)和异步(...
Kubernetes安装与集群... 一、环境准备 1、机器环境前置条件 当前演示准备3台虚拟机环境,或者是3台阿里云服务器...
simscape仿真总结2-机... 最近用simscape进行机器人的仿真,记录和总结一下学习心得和踩过的坑。 参照B站...
Redis(一):数据结构-底... 前言 从本文开始,我将分享一下近期自学 Redis 的学习笔记,其中大部...
flask教程5:abort函... 文章目录一、abort()函数的使用1.传递状态码信息2.传递响应体消息二、自定义错误处理 app....
【玩转Jetson TX2 N... 1 VMware14 Workstation Pro安装 如果没有Ubuntu系统电脑,...
2023还有人不知道kuber... 文章目录Kubernetes(K8s)一、Openstack&VM1、**认识虚拟化****1.1*...
NOI2019模拟赛 T1牛油... 题目描述 牛油果是一种神秘的水果,其具有一个坚固程度x≥0x\geq 0x≥0...
嵌入式软件开发之Linux下C... 目录 前沿 Hello World! 编写代码 编译代码 GCC编译器  gcc 命...
云原生|Rancher与Ope... 目录一、Rancher(一)介绍(二)优点&...
如何突破卫星影像建模难点?重建... 日前,由重建大师生成的首个“珞珈三号01星”卫星影像三维模型一经发出,引...
L1-085 试试手气 L1... 我们知道一个骰子有 6 个面,分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状...
SpringSecurity客... 概述 FilterChainProxy是spring-security的入口,包含默认...
数据结构--二叉树 目录1.树概念及结构1.1数的概念1.2数的表示2.二叉树概念及结构2.1二叉树的概念2.2数据结构...
Qt之QUrl和QUrlQue... QUrlQUrl 类提供了一个方便的接口使用 URLs。最常见的使用QUrl 的方式是通过构造函数来...
函数指针二三事 1 什么是函数指针? ​ 函数指针,顾名思义,它是一个指向...
[ 红队知识库 ] Windo... 🍬 博主介绍 👨‍🎓 博主介绍:大家好...
【PowerBI】PowerB... 目的: 陈述PowerBI连接Mysql数据库的坑。 方法1:直接使用【...
BI数据可视化|可自动刷新的可... BI数据可视化大屏和其他的BI报表一样,都是可用于日常的决策中,因此除了...
Linux 练习十二 (Lin... 文章目录1 计算机网络基础知识1.1 OSI参考模型和TCP/IP参考模型1.2 TCP 协议1.2...
SQL语言基础教学 | Mys... SQL语言基础教学SQL(Structured Query Languageÿ...
pandas数据分析(三) 书接pandas数据分析(二) 文章目录DataFrame数据处理与分...
DC-DC升压模块隔离高压稳压... 特点● 效率高达 80%● 2*2英寸标准封装● 单双电压输出● 价格低● 大于600V高压,稳压输...
Java【多线程基础2】 Th... 文章目录前言一、Thread类1, 构造方法2, 常用成员属性3, 常用成员方法3.1, start...
TDK| 电源——反激变压器设... 电源参数根据功率、输入输出的情况,我们选择反激电源拓扑。反激式变压器的优点有:1、 电...
Python:判断语句 目录一、布尔类型1.1定义1.2获取二、逻辑运算符2.1and运算符2.2or运算符2.2not运算...
协程池加disruptor加e... 先说一下disrutor和协程的实现。然后介绍服务器具体分析,以及迭代过程,项目困难,学到东西,压测...
selenium(2)----... 操作界面上的元素: 先选中元素再进行调用下面的方法 1)click(),点击对象 2)...
第九章:C语言数据结构与算法初... 系列文章目录 文章目录系列文章目录前言一、堆的定义二、堆的实现三、堆的接口函数1、初始化2、销毁3...
< Linux > 多线程(单... 目录 1、单例模式         饿汉方式实现单例模式         懒汉方式实现单例模式   ...