首页 > 其他分享 >生产者-消费者问题(转)

生产者-消费者问题(转)

时间:2023-04-20 17:47:55浏览次数:22  
标签:消费者 生产者 婊子 next 问题 缓冲区 数据

原文:https://zhuanlan.zhihu.com/p/259541449

又称有限缓冲问题(英语:Bounded-buffer problem),是一个多进程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个进程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据

要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法[1]等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

生产者-消费者模型解决的问题

在生产者/消费者模型中,生产者Producer负责生产数据,而消费者Consumer负责使用数据。多个生产者线程会在同一时间运行,生产数据,并放到内存中一个共享的区域

生产者线程-消费者线程:

生产者线程用于生产数据,另一种是消费者线程用于消费数据,为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库,生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为;

而消费者只需要从共享数据区中去获取数据,就不再需要关心生产者的行为。但是,这个共享数据区域中应该具备这样的线程间并发协作的功能:

  • 如果共享数据区已满的话,阻塞生产者继续生产数据放置入内;
  • 如果共享数据区为空的话,阻塞消费者继续消费数据;

生产者消费者模型的优点

支持并发

由于生产者与消费者是两个独立的并发体,他们之间是用缓冲区作为桥梁连接,生产者只需要往缓冲区里丢数据,

就可以继续生产下一个数据,而消费者只需要从缓冲区了拿数据即可,这样就不会因为彼此的处理速度而发生阻塞。

接上面的例子,如果我们不使用邮筒,我们就得在邮局等邮递员,直到他回来,

我们把信件交给他,这期间我们啥事儿都不能干(也就是生产者阻塞),或者邮递员得挨家挨户问,谁要寄信(相当于消费者轮询)。

解耦

假设生产者和消费者分别是两个类。

如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。

将来如果消费者的代码发生变化, 可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。

举个例子,我们去邮局投递信件,如果不使用邮筒(也就是缓冲区),你必须得把信直接交给邮递员。

有同学会说,直接给邮递员不是挺简单的嘛?其实不简单,你必须 得认识谁是邮递员,才能把信给他(光凭身上穿的制服,万一有人假冒,就惨了)。

这就产生和你和邮递员之间的依赖(相当于生产者和消费者的强耦合)。

万一哪天邮递员换人了,你还要重新认识一下(相当于消费者变化导致修改生产者代码)。

而邮筒相对来说比较固定,你依赖它的成本就比较低(相当于和缓冲区之间的弱耦合)。

支持忙闲不均

缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。

当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。 等生产者的制造速度慢下来,消费者再慢慢处理掉。

为了充分复用,我们再拿寄信的例子来说事。假设邮递员一次只能带走1000封信。万一某次碰上情人节(也可能是圣诞节)送贺卡,

需要寄出去的信超过1000封,这时 候邮筒这个缓冲区就派上用场了。邮递员把来不及带走的信暂存在邮筒中,等下次过来 时再拿走。

 举例:
 1 #生产者和消费者,使用生成器的方式,就是一个简单的并行,
 2 import time
 3 # 这是一个消费者 一直在等待完成吃包子的动作
 4 def consumer(name):
 5     print('%s准备打小三了!'%name)  #打印出对应的消费者的名字
 6     while True:   #执行一个死循环 实际上就是需要调用时才会执行,没有调用就会停止在yield
 7         baozi = yield  #在它就收到内容的时候后就把内容传给baozi
 8         print('小三【%s】来了,被【%s】打了'%(biaozi,name))
 9 def producer(name):
10     c1 = consumer('A')  #它只是把c1变成一个生成器
11     c2 = consumer('B')
12     c1.__next__() #第一个next只是会走到yield然后停止
13     c2.__next__()
14     print('婊子开始做小三了')
15     for i in range(1,10):
16         time.sleep(1)
17         print('三年打了两个婊子')
18         c1.send(i)  #这一步其实就是调用next方法的同时传一个参数i给field接收,然后baozi=i
19         c2.send(i+1)
20         #其实这里是这样的,在send的时候只是继续执行yield下面的语句,然后去去yield,再次停在这儿
21 
22 # producer('aea')
23 c = consumer('aaa') #没next一次就会将程序执行一次
24 c.__next__()
25 c.__next__()
26 c.__next__()
27 **out:**
28 
29 
30 A准备打小三了!
31 B准备打小三了! 
32 婊子开始做小三了
33 三年打了两个婊子
34 小三【1】来了,被【A】打了
35 小三【2】来了,被【B】打了
36 三年打了两个婊子
37 小三【2】来了,被【A】打了
38 小三【3】来了,被【B】打了
39 三年打了两个婊子
40 小三【3】来了,被【A】打了
41 小三【4】来了,被【B】打了
42 三年打了两个婊子
43 小三【4】来了,被【A】打了
44 小三【5】来了,被【B】打了
45 三年打了两个婊子
46 小三【5】来了,被【A】打了
47 小三【6】来了,被【B】打了
48 三年打了两个婊子
49 小三【6】来了,被【A】打了
50 小三【7】来了,被【B】打了
51 三年打了两个婊子
52 小三【7】来了,被【A】打了
53 小三【8】来了,被【B】打了
54 三年打了两个婊子
55 小三【8】来了,被【A】打了
56 小三【9】来了,被【B】打了
57 三年打了两个婊子
58 小三【9】来了,被【A】打了
59 小三【10】来了,被【B】打了
60 光头强准备打小三了!
61 小三【None】来了,被【光头强】打了
62 小三【None】来了,被【光头强】打了

 

标签:消费者,生产者,婊子,next,问题,缓冲区,数据
From: https://www.cnblogs.com/tan-wm/p/17337683.html

相关文章

  • 共享库的问题
    1.新安装的程序运行时找不到动态库,若共享库安装到了/lib或/usr/lib那么需要执行以下ldconfig,ldconfig的作用是在默认搜索路径/lib和/usr/lib和动态库配置文件/etc/ld.so.conf所列的目录下搜索出动态链接库。2.若共享库安装到了/usr/local/lib下,那么执行ldconfig之前需要把......
  • 高新技术企业申报有哪些常见问题
    高新技术企业高新技术企业是指在中国(不包括香港、澳门、台湾)注册一年以上的居民企业,在国家重点支持的高新技术领域不断开展研发和技术成果转化,形成企业核心自主知识产权,并在此基础上开展经营活动。高新技术企业作为国家重点发展对象,不仅享受国家政策,还享受地方政策支持。那么,企业如......
  • EasyCVR视频融合平台语音对讲设备端异常的问题分析及解决
    EasyCVR平台属于综合性及融合性较强的视频平台,目前可支持多协议、多类型的海量设备接入与分发,具备视频监控直播、云端录像、录像的检索与回看、存储、智能告警、语音对讲、平台级联、跨系统支持、灵活网络环境配置等视频能力,在线下均有大量落地应用。我们在此前的文章中也介绍过关......
  • umy-ui表格单行编辑(解决单行编辑滑动后失效问题)
    TableRowEdit.vue<template><div><ux-grid:data="tableData"tooltip-effect="dark"show-overflow="tooltip":cell-style="{'text-align':'center'}&q......
  • MySQL使用过程中常见问题的解决
    问题1:root用户密码忘记,重置的操作、1:通过任务管理器或者服务管理,关掉mysqld(服务进程)2:通过命令行+特殊参数开启mysqldmysqld--defaults-file="D:\ProgramFiles\mysql\MySQLServer5.7Data\my.ini"--skip-grant-tables3:此时,mysqld服务进程已经打开。并且不需......
  • 正版Abaqus软件价格贵?许可优化可解决预算不足许可不够用问题!
    随着计算机技术的发展和普及,各类软件已经成为现代生产和研究工作的重要工具。ABAQUS软件作为有限元分析软件的代表,具有广泛的应用领域和丰富的功能,成为了科研机构和企业所青睐的工具之一。然而,其高昂的许可证价格,往往使得机构和企业难以承担。针对这一问题,本文围绕浮点许可优化管理......
  • 28 27 | 主库出问题了,从库怎么办?
    在前面的第24、25和26篇文章中,我和你介绍了MySQL主备复制的基础结构,但这些都是一主一备的结构。大多数的互联网应用场景都是读多写少,因此你负责的业务,在发展过程中很可能先会遇到读性能的问题。而在数据库层解决读性能问题,就要涉及到接下来两篇文章要讨论的架构:一主多从。今天这......
  • 30 29 | 如何判断一个数据库是不是出问题了?
    我在第25和27篇文章中,和你介绍了主备切换流程。通过这些内容的讲解,你应该已经很清楚了:在一主一备的双M架构里,主备切换只需要把客户端流量切到备库;而在一主多从架构里,主备切换除了要把客户端流量切到备库外,还需要把从库接到新主库上。主备切换有两种场景,一种是主动切换,一种是被动......
  • 轻松应对同一IP被封禁的问题:HTTP代理对于爬虫的重要性
    在网络爬虫的世界里,遇到IP被封禁的问题是非常普遍的。不过,我们可以采取一些措施来应对这个问题,其中一个重要的措施就是使用HTTP代理。HTTP代理是一种能够隐藏真实IP地址并改变访问路径的技术,它可以将爬虫的请求发送到代理服务器中,再由代理服务器向目标服务器发起请求,从而避......
  • 从根源上解决反爬虫问题——HTTP代理的应用
    你是不是经常遇到在爬取网站数据时被封IP,或者访问速度过慢的情况呢?这就是因为网站为了保护自己的数据不被恶意利用,采取了反爬虫技术。但是,现在有一种解决方法——HTTP代理。HTTP代理可以将你的请求都转发到一个代理服务器上,然后由代理服务器再去访问目标网站。这样的好处在......