5 并发编程-(进程)-队列&生产者消费者模型
1、队列的介绍
进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
创建队列的类(底层就是以管道和锁定的方式实现):
Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
参数介绍:
- maxsize是队列中允许最大项数,省略则无大小限制。
- 但需要明确:
- 1、队列内存放的是消息而非大数据
- 2、队列占用的是内存空间,因而maxsize即便是无大小限制也受限于内存大小
主要方法:
- q.put方法用以插入数据到队列中。
- q.get方法可以从队列读取并且删除一个元素。
- from multiprocessing import Process,Queue
- q=Queue(3)
- #put ,get ,put_nowait,get_nowait,full,empty
- q.put(1)
- q.put(2)
- q.put(3)
- print(q.full()) #满了
- # q.put(4) #再放就阻塞住了
- print(q.get())
- print(q.get())
- print(q.get())
- print(q.empty()) #空了
- # print(q.get()) #再取就阻塞住了
- True
- 1
- 2
- 3
- True
二、生产者消费者模型
1、生产者消费者模型介绍
为什么要使用生产者消费者模型
生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,
如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,
才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。
为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者和消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
这个阻塞队列就是用来给生产者和消费者解耦的
2、生产者消费者模型实现
2.1 引入模型(生产一个消费一个)
- import time
- def producer():
- for i in range(3):
- res = f"包子 {i}"
- time.sleep(0.5)
- print(f"生产者生产了{res}")
- consumer(res)
- def consumer(res):
- time.sleep(1)
- print(f"消费者吃了{res}")
- if __name__ == '__main__':
- producer()
- 生产者生产了包子 0
- 消费者吃了包子 0
- 生产者生产了包子 1
- 消费者吃了包子 1
- 生产者生产了包子 2
- 消费者吃了包子 2
2.2 实现生产者消费者模型,但有小问题主进程永远不会结束
消费者不知道生产者已经完毕,一直处于等待状态,死循环
- from multiprocessing import Process,Queue
- import time
- def producer(q):
- for i in range(3):
- res = f"包子 {i}"
- time.sleep(0.5)
- print(f"生产者生产了{res}")
- # 把生产的给队列保存
- q.put(res)
- def consumer(q):
- while True:# 消费者一直接收
- res = q.get()
- time.sleep(1)
- print(f"消费者吃了{res}")
- if __name__ == '__main__':
- q = Queue()
- p1 = Process(target=producer,args=(q,))
- p2 = Process(target=consumer,args=(q,))
- p1.start()
- p2.start()
- print('主')
- 主
- 生产者生产了包子 0
- 生产者生产了包子 1
- 生产者生产了包子 2
- 消费者吃了包子 0
- 消费者吃了包子 1
- 消费者吃了包子 2
此时的问题是主进程永远不会结束,原因是:生产者p在生产完后就结束了,但是消费者c在取空了q之后,则一直处于死循环中且卡在q.get()这一步。
解决方式无非是让生产者在生产完毕后,往队列中再发一个结束信号,这样消费者在接收到结束信号后就可以break出死循环
2.3、解决办法--低阶--生产者通知消费者生产结束
队列先进先出
- from multiprocessing import Process,Queue
- import time
- def producer(q):
- for i in range(3):
- res = f"包子 {i}"
- time.sleep(0.5)
- print(f"生产者生产了{res}")
- # 把生产的给队列保存
- q.put(res)
- def consumer(q):
- while True:# 消费者一直接收
- res = q.get()
- if res == None:
- break
- time.sleep(1)
- print(f"消费者吃了{res}")
- if __name__ == '__main__':
- q = Queue()
- p1 = Process(target=producer,args=(q,))
- p2 = Process(target=consumer,args=(q,))
- p1.start()
- p2.start()
- p1.join()# 主进程等待p1子进程执行完毕--即生产者生产完毕
- q.put(None)
- print('主')
- 生产者生产了包子 0
- 生产者生产了包子 1
- 生产者生产了包子 2
- 消费者吃了包子 0
- 主
- 消费者吃了包子 1
- 消费者吃了包子 2
但上述解决方式,在有多个生产者和多个消费者时,我们则需要用一个很low的方式去解决,有几个消费者就需要发送几次结束信号:相当low,例如
- if __name__ == '__main__':
- q=Queue()
- #生产者们:即厨师们
- p1=Process(target=producer,args=(q,'egon1','包子'))
- p2=Process(target=producer,args=(q,'egon2','骨头'))
- p3=Process(target=producer,args=(q,'egon3','泔水'))
- #消费者们:即吃货们
- c1=Process(target=consumer,args=(q,'alex1'))
- c2=Process(target=consumer,args=(q,'alex2'))
- #开始
- p1.start()
- p2.start()
- p3.start()
- c1.start()
- c2.start()
- p1.join()
- p2.join()
- p3.join()
- q.put(None)
- q.put(None)
- q.put(None)
- print('主')
2.4 JoinableQueue([maxsize]) 解决办法--高阶--消费者通知生生产者 项目已经被成功处理
- 这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。
- JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
- q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
- q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
- from multiprocessing import Process,JoinableQueue
- import time
- def producer(q):
- for i in range(2):
- res = f"包子 {i}"
- time.sleep(0.5)
- print(f"生产者生产了{res}")
- # 把生产的给队列保存
- q.put(res)
- q.join()#等待消费者把自己放入队列中的所有的数据都取走之后,消费者才结束
- def consumer(q):
- while True:# 消费者一直接收
- res = q.get()
- # if res == None:
- # break
- time.sleep(1)
- print(f"消费者吃了{res}")
- q.task_done() #发送信号给q.join() 说明已经从队列中取走一个数据并处理完毕了
- if __name__ == '__main__':
- q = JoinableQueue()
- p1 = Process(target=producer,args=(q,))
- p2 = Process(target=producer,args=(q,))
- p3 = Process(target=producer,args=(q,))
- #------消费者--------
- c1 = Process(target=consumer,args=(q,))
- c2 = Process(target=consumer,args=(q,))
- # 守护进程,消费者设置成守护进程,主进程结束完后 消费者 结束
- c1.daemon = True
- c2.daemon = True
- p1.start()
- p2.start()
- p3.start()
- c1.start()
- c2.start()
- p1.join()
- p2.join()
- p3.join()
- print('主')
3、总结
1、程序中有两类角色
一类负责生产数据(生产者)
一类负责处理数据(消费者)
2、引入生产者消费者模型为了解决的问题是
平衡生产者与消费者之间的速度差
程序解开耦合
3、如何实现生产者消费者模型
生产者<--->队列<--->消费者
5 并发编程-(进程)-队列&生产者消费者模型的更多相关文章
- 【Java并发编程】:生产者—消费者模型
生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据“姓 ...
- #queue队列 #生产者消费者模型
#queue队列 #生产者消费者模型 #queue队列 #有顺序的容器 #程序解耦 #提高运行效率 #class queue.Queue(maxsize=0) #先入先出 #class queue.L ...
- python网络编程--进程(方法和通信),锁, 队列,生产者消费者模型
1.进程 正在进行的一个过程或者说一个任务.负责执行任务的是cpu 进程(Process: 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在 ...
- python 全栈开发,Day39(进程同步控制(锁,信号量,事件),进程间通信(队列,生产者消费者模型))
昨日内容回顾 python中启动子进程并发编程并发 :多段程序看起来是同时运行的ftp 网盘不支持并发socketserver 多进程 并发异步 两个进程 分别做不同的事情 创建新进程join :阻塞 ...
- python 进程锁 生产者消费者模型 队列 (进程其他方法,守护进程,数据共享,进程隔离验证)
#######################总结######### 主要理解 锁 生产者消费者模型 解耦用的 队列 共享资源的时候 是不安全的 所以用到后面的锁 守护进程:p.daem ...
- Learning-Python【34】:进程之生产者消费者模型
一.什么是生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样 ...
- Day034--Python--锁, 信号量, 事件, 队列, 生产者消费者模型, joinableQueue
进程同步: 1. 锁 (重点) 锁通常被用来实现对共享资源的同步访问.为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁, ...
- python2.0_s12_day9之day8遗留知识(queue队列&生产者消费者模型)
4.线程 1.语法 2.join 3.线程锁之Lock\Rlock\信号量 4.将线程变为守护进程 5.Event事件 * 6.queue队列 * 7.生产者消费者模型 4.6 queue队列 que ...
- 队列&生产者消费者模型
队列 ipc机制:进程通讯 管道:pipe 基于共享的内存空间 队列:pipe+锁 queue from multiprocessing import Process,Queue ### 案例一 q ...
随机推荐
- JVM(上)
堆.栈 JVM内存≍Heap(堆内存)+PermGen(方法区)+Thrend(栈)Heap(堆内存)=Young(年轻代)+Old(老年代),官方文档建议整个年轻代占整个堆内存的3/8,老年代占整个 ...
- 测试开发系列之Python开发mock接口(一)
什么是mock接口呢,举个栗子,你在一家电商公司,有查看商品.购物.支付.发 货.收获等等等一大堆功能,你是一个测试人员,测测测,测到支付功能的时候,你就要调用第三方支付接口了,真实支付,直接扣你支付 ...
- led的驱动及测试程序
一.驱动源码 #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> # ...
- Django安装与介绍
安装 Django是以Python为语言环境的,所以要先确保计算机上已经安装了Python. Linux ubuntu: sudo pip install Django==1.11.7 安装中指定了版 ...
- bzoj1034 泡泡堂
Description 第XXXX届NOI期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由n名选手组成,比赛的项目是老少咸宜的网络游戏泡泡堂.每一场比赛前,对阵 ...
- MongoDB CPU 利用率高,分析慢请求
Jemeter 压测过程,发现mongodb的CPU均达到100%,需要查看mongodb的执行情况,使用mongo自带的profiling功能. profiling将请求的执行情况记录在DB下的 s ...
- Linux版本使用的文件系统类型
1. cat /etc/fstab 2. df -T -h
- Spark分析之Master
override def preStart() { logInfo("Starting Spark master at " + masterUrl) webUi.bind() // ...
- Flex知识
转载:http://www.cnblogs.com/xia520pi/archive/2011/12/11/2283851.html
- css border-bottom(指定下边线的样式、宽度及颜色)
border-bottom(指定下边线的样式.宽度及颜色) border-bottom: 值: border-bottom-style:值; border-bottom-color: 值; borde ...