(python)生产者消费者模型

article/2025/9/12 15:44:18

    生产者消费者模型当中有两大类重要的角色,一个是生产者(负责造数据的任务),另一个是消费者(接收造出来的数据进行进一步的操作)。

为什么要使用生产者消费者模型?

     在并发编程中,如果生产者处理速度很快,而消费者处理速度比较慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个等待的问题,就引入了生产者与消费者模型。让它们之间可以不停的生产和消费。

实现生产者消费者模型三要素:

    1、生产者

    2、消费者

    3、队列(或其他的容哭器,但队列不用考虑锁的问题)

什么时候用这个模型?

程序中出现明显的两类任务,一类任务是负责生产,另外一类任务是负责处理生产的数据的(如爬虫)

用该模型的好处?

1、实现了生产者与消费者的解耦和

2、平衡了生产力与消费力,就是生产者一直不停的生产,消费者可以不停的消费,因为二者不再是直接沟通的,而是跟队列沟通的。

来简单的写一个生产者消费者模型:

import time
import random
from multiprocessing import Queue,Processdef consumer(name,q):while True:res=q.get()time.sleep(random.randint(1,3))print('消费者》》%s 准备开吃%s。'%(name,res))def producer(name,q):for i in range(5):time.sleep(random.randint(1,2))res='大虾%s'%iq.put(res)print('生产者》》》%s 生产了%s'%(name,res))if __name__ == '__main__':q=Queue()#一个队列p1=Process(target=producer,args=('monicx',q))c1=Process(target=consumer,args=('lili',q))p1.start()c1.start()

运行效果:


现在确实让生产者不停的生产,消费者不断的消费。,但此时有一个问题就是主进程没有结束。原因是:生产者p1生产完后就结束了,但是消费者c1,在q.get()取空之后,就一直在原地等待。解决这个问题无非就让生产者在生产完毕后,就再往队列中发送一个结束信号,这样消费者接收到结束信号后就可以跳出死循环。

import time
import random
from multiprocessing import Queue,Processdef consumer(name,q):
    while True:
        res=q.get()if res is None:break
        time.sleep(random.randint(1,3))print('消费者》》%s 准备开吃%s。'%(name,res))def producer(name,q):
    for i in range(5):
        time.sleep(random.randint(1,2))
        res='大虾%s'%iq.put(res)print('生产者》》》%s 生产了%s'%(name,res))if __name__ == '__main__':
    q=Queue()#一个队列

    p1=Process(target=producer,args=('monicx',q))c1=Process(target=consumer,args=('lili',q))p1.start()c1.start()p1.join()q.put(None)

运行结果:


虽然解决了问题,但是这种的解决方式,在有多个生产者和多个消费者时,有几个消费者就要发送几次的结束信号,不然程序就不会停止。相当的low。就像这样:

import time
import random
from multiprocessing import Queue,Processdef consumer(name,q):
    while True:
        res=q.get()if res is None:break
        time.sleep(random.randint(1,3))print('消费者》》%s 准备开吃%s。'%(name,res))def producer(name,q):
    for i in range(5):
        time.sleep(random.randint(1,2))
        res='大虾%s'%iq.put(res)print('生产者》》》%s 生产了%s'%(name,res))if __name__ == '__main__':
    q=Queue()#实例一个队列

    p1=Process(target=producer,args=('monicx1',q))p2=Process(target=producer,args=('monicx2',q))c1=Process(target=consumer,args=('lili1',q))c2=Process(target=consumer,args=('lili2',q))c3=Process(target=consumer,args=('lili3',q))p1.start()p2.start()c1.start()c2.start()c3.start()p1.join()p2.join()q.put(None)q.put(None)q.put(None)

我们的思路就是发送结束信号而已,有另外一种队列提供了这种机制。

JoinableQueue([maxsize])

这就像是一个Queue对象,但队列允许项目的使用者通知生产者项目已经被处理。通知进程是使用共享的信号和条件变量来实现的。

其中maxsize是队列中允许最大项数,省略则无大小限制。

JoinableQueue的实例q除了与Queue对象相同的方法之外还具有:

task_done():消费者用此方法发出信息,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将会导致ValueError异常。

join():生产者调用此方法进行阻塞,直到队列中所有的项目都被处理了。

import time
import random
from multiprocessing import Process
from multiprocessing import JoinableQueuedef consumer(name,q):while True:res=q.get()time.sleep(random.randint(1,3))print('\033[43m消费者》》%s 准备开吃%s\033[0m'%(name,res))q.task_done()#发送信号给生产者的q.join()说,已经处理完从队列中拿走的一个项目def producer(name,q):for i in range(5):time.sleep(random.randint(1,2))#模拟生产时间res='大虾%s'%iq.put(res)print('\033[40m生产者》》》%s 生产了%s\033[0m'%(name,res))q.join()#等到消费者把自己放入队列中的所有项目都取走处理完后调用task_done()之后,生产者才能结束if __name__ == '__main__':q=JoinableQueue()#实例一个队列p1=Process(target=producer,args=('monicx1',q))p2=Process(target=producer,args=('monicx2',q))c1=Process(target=consumer,args=('lili1',q))c2=Process(target=consumer,args=('lili2',q))c3=Process(target=consumer,args=('lili3',q))c1.daemon=Truec2.daemon=Truec3.daemon=Truep1.start()p2.start()c1.start()c2.start()c3.start()p1.join()p2.join() 

运行结果:



http://chatgpt.dhexx.cn/article/QQE9FPvc.shtml

相关文章

【生产者消费者模型】

Linux生产者消费者模型 生产者消费者模型生产者消费者模型的概念生产者消费者模型的特点生产者消费者模型优点 基于BlockingQueue的生产者消费者模型基于阻塞队列的生产者消费者模型模拟实现基于阻塞队列的生产消费模型 生产者消费者模型 生产者消费者模型的概念 生产者消费者…

【Linux】生产者消费者模型 - 详解

目录 一.生产者消费者模型概念 1.为何要使用生产者消费者模型 2.生产者消费者之间的关系 3.生产者消费者模型的优点 二.基于阻塞队列的生产消费模型 1.在阻塞队列中的三种关系 2.BlockingQueue.hpp - 阻塞队列类 3.LockGurad.hpp - RAII互斥锁类 4.Task.hpp - 在阻塞队…

操作系统 —— 生产者消费者模型

文章目录 1. 生产者消费者模型的理解1.1 串行的概念1.2 并行的概念1.3 简单总结: 2. 基于阻塞队列(block queue)实现此模型2.1 阻塞队列的实现2.2 使用阻塞队列,单线程2.3 使用阻塞队列,多线程2.4 总结:阻塞队列实现的消费者生产者…

生产者消费者案例

目录 前言一、案例描述二、创建快递柜三、创建生产者类四、创建消费者类五、测试类总结 前言 生产者消费者模式属于一种经典的多线程协作的模式,弄清生产者消费者问题能够让我们对于多线程编程有更深刻的理解,下面,为大家分享一个生产者消费…

JAVA多线程之生产者消费者模型

生产者消费者模型 所谓的生产者消费者模型,是通过一个容器来解决生产者和消费者的强耦合问题。通俗的讲,就是生产者在不断的生产,消费者也在不断的消费,可是消费者消费的产品是生产者生产的,这就必然存在一个中间容器&…

Linux生产者消费者模型

文章目录 生产者消费者模型生产者消费者模型的概念生产者消费者模型的特点生产者消费者模型优点 基于BlockingQueue的生产者消费者模型基于阻塞队列的生产者消费者模型模拟实现基于阻塞队列的生产消费模型 生产者消费者模型 生产者消费者模型的概念 生产者消费者模式就是通过一…

生产者消费者模型你知道多少

背景 进入正题之前先说点故事。从最开始学java的那里开始:我是从08年下半年开始学Java,在《我的六年程序之路》中提到了一些。当时比较简单,每天看尚学堂的视频(对于初学者而言看视频好一些。),然后写代码。…

生产者消费者模型详解

生产者消费者模型 文章目录 生产者消费者模型什么是生产者消费者模型基于BlockingQueue的生产者消费者模型单生产者单消费者模型多生产者多消费者模型 什么是生产者消费者模型 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接…

Python -- 生产者消费者

代码 # -*- coding: utf-8 -*- # Author : markadc # Time : 2021/4/14 11:43from queue import Queue import time import threading# maxsize: 指定队列最大长度 q Queue(maxsize10)# 生产者 def product(name):count 0while True:# 只要队列没有满,就一直…

生产者与消费者

生产者和消费者 目录 生产者和消费者1.什么是生产者和消费者2.生产者和消费者(不加唤醒机制)3.生产者和消费者(加唤醒机制)4.解决虚假唤醒5.使用lock锁6.面试题 1.什么是生产者和消费者 ​ 在日常生活中,我们去商店买东西,我们就是消费者,商…

三种方式实现生产者-消费者模型

前言 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的…

生产者消费者模型

目录 一、生产者消费者模型的概念 二、生产者消费者模型的特点 三、生产者消费者模型优点 四、基于BlockingQueue的生产者消费者模型 4.1 基本认识 4.2 模拟实现 五、POSIX信号量 5.1 信号量概念 5.2 信号量函数 5.2.1 初始化信号量 5.2.2 销毁信号量 5.2.3 等待信…

打家劫舍问题

打家劫舍问题 最近碰见这种问题实在是太多了,感觉还是有必要学习一下打家劫舍以及其变种问题这一类问题采用的都是动态规划的解法 一些练习题目 6378. 最小化旅行的价格总和 198. 打家劫舍I 213. 打家劫舍 II 337. 打家劫舍 III 2560. 打家劫舍 IV 1 、打家劫舍I 题目…

经典动态规划:打家劫舍系列问题

打家劫舍系列总共有三道,难度设计非常合理,层层递进。第一道是比较标准的动态规划问题,而第二道融入了环形数组的条件,第三道更绝,让盗贼在二叉树上打劫. House Robber | public int rob(int[] nums);题目很容易理解…

【算法】动态规划(三)——打家劫舍系列问题

目录 一、前言 二、打家劫舍 (1)198. 打家劫舍Ⅰ • 整体代码: (2)213. 打家劫舍 II • 题目分析 • 整体代码: (3)337. 打家劫舍Ⅲ • 思路分析 • 整体代码: 三、补充知…

动态规划之打家劫舍系列

前言 打家劫舍问题是一种非常经典的有限制条件的动态规划问题,按理说,不是一种特殊的类型,但是因为力扣上纯纯的出了三道题(1,2,3)来考察,题目的难度是依次递进的,还结合…

动态规划之打家劫舍

动态规划之打家劫舍 文章目录 动态规划之打家劫舍1. "198. 打家劫舍"2. "198. 打家劫舍(变种:输出路径)"3. "213. 打家劫舍 II"4. "337. 打家劫舍 III" 1. “198. 打家劫舍” dp数组定义&#xff1a…

oracle 根据部分字段去重

问题:在oracle中使用group by分组,group by子句中必须包含所有的select中的字段和order by子句中的字段。 在不使用group by子句的情况下,进行分组。(根据部分字段分组) over()分析函数 原sql SELECTIM. ID mediaGrou…

oracle字段去重查询,oracle怎么去重查询

oracle去重查询的方法是: oracle 数据库多字段去重 方法介绍:distinct 关键字、group by 、row_number ()over(partition by 列 order by 列 desc) 我的需求是:根据某几列去重 查询出去重后的全部信息。最后我选择的是第三种方法。 我的想法&…

oracle 数据去重方法

1. 创建表: -- Create table create table TEST_USER (user_id NUMBER(3),user_name VARCHAR2(20),user_age NUMBER(3) ) tablespace GUAN_TABLESPACEpctfree 10initrans 1maxtrans 255storage(initial 64Knext 1Mminextents 1maxextents unlimited);--测试数据…