一 生产者消费者模型介绍

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

生产者指的是生产数据的任务,消费者指的是处理数据的任务,

生产数据目的,是为了给消费者处理。

在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

import time

def producer():
'''生产者是厨师''' for i in range(1,4): # 模拟生产三个数据
res = "包子%s" % i
time.sleep(2)
print("生产者生产%s" % res) consumer(res) def consumer(res):
'''消费者吃包子''' time.sleep(1)
print("消费者消费%s" % res) if __name__ == "__main__":
producer() '''
生产者生产包子1
消费者消费包子1
生产者生产包子2
消费者消费包子2
生产者生产包子3
消费者消费包子3
'''

生产者必须等消费者,消费者也必须等生产者!

什么是生产者和消费者模型

生产者消费者模型是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

+

这个阻塞队列就是用来给生产者和消费者解耦的

二 生产者消费者模型实现

通过队列

from multiprocessing import Process
from multiprocessing import Queue
import time def producer(q): for i in range(1,6):
res = "包子%s" %i
time.sleep(0.5)
print("生产者生产%s" % res) # 现在不是给消费者了 放入数据 res 把包子放到队列
q.put(res) def consumer(q):
while True:
# 一直接取数据
res = q.get()
time.sleep(1)
print("消费者消费%s" % res) if __name__ == "__main__": # 容器
q = Queue() # 生产者们
# 需要传参数 把生产后数据的往队列里丢
p = Process(target=producer, args=(q,)) # 消费者们
c = Process(target=consumer, args=(q,)) p.start()
c.start()
print("主")

执行结果,不是生产一个消费一个,生成者与消费者互相不影响


生产者生产包子1
生产者生产包子2
生产者生产包子3
消费者消费包子1
生产者生产包子4
生产者生产包子5
消费者消费包子2
消费者消费包子3
消费者消费包子4
消费者消费包子5

此时的问题是主进程永远不会结束

原因是:生产者p在生产完后就结束了,但是消费者c在取空了队列之后,则一直处于死循环中且卡在q.get()这一步。(生产者从队列取不到数据就卡住)

一旦队列取空了 会被锁住 就卡住了,程序卡在消费者

解决:

解决方式无非是让生产者在生产完毕后,往队列中再发一个结束信号,这样消费者在接收到结束信号后就可以break出死循环

from multiprocessing import Process
from multiprocessing import Queue
import time def producer(q): for i in range(1,6):
res = "包子%s" %i
time.sleep(0.5)
print("生产者生产%s" % res) # 现在不是给消费者了 放入数据 res 把包子放到队列
q.put(res) def consumer(q):
while True:
# 接取数据
res = q.get()
# 消费者在最后一次收到None后退出
if res is None:break
time.sleep(1)
print("消费者消费%s" % res) if __name__ == "__main__": # 容器
q = Queue() # 生产者们
# 需要传参数 把生产后数据的往队列里丢
p = Process(target=producer, args=(q,)) # 消费者们
c = Process(target=consumer, args=(q,)) p.start()
c.start() # 保证所有子进程执行完 主进程才能工作,不然一直阻塞
p.join()
# 保证生产者把所有数据扔到队列后 然后发送结束信号
q.put(None)
print("主") '''
生产者生产包子1
生产者生产包子2
生产者生产包子3
消费者消费包子1
生产者生产包子4
生产者生产包子5
消费者消费包子2

消费者消费包子3
消费者消费包子4
消费者消费包子5
'''

如果有多个消费者 生产者时候

有几个消费者就需要发送几次结束信号

from multiprocessing import Process, Queue
import time def producer(q): for i in range(5):
res = "包子%s" %i
time.sleep(0.5)
print("生产者生产%s" % res) # 现在不是给消费者了 放入数据 res 把包子放到队列
q.put(res) def consumer(q):
while True:
# 接取数据
res = q.get()
if res is None:break
time.sleep(1)
print("消费者消费%s" % res) if __name__ == "__main__": # 容器
q = Queue() # 生产者们
# 需要传参数 把生产后数据的往队列里丢
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,)) p1.start()
p2.start()
p3.start() c1.start()
c2.start() # 保证所有子进程执行完 主进程才能工作,不然一直阻塞
p1.join()
p2.join()
p3.join() # 发完数据后 发送结束信号 有几个消费者就应该来几个信号 q.put(None)
q.put(None)
print("主")

结束信号一定是跟在正常数据后面,保证所有消费者把正常数据取走以后,接下来取的是结束信号

结束信号应该在主进程里面确保所有的生产者,都生产完毕以后,才发送结束信号

其实我们的思路无非是发送结束信号而已,有另外一种队列提供了这种机制 可以点击这个文章

JoinableQueue

python 并发编程 多进程 生产者消费者模型介绍的更多相关文章

  1. python 并发编程 多进程 生产者消费者模型总结

    生产者消费者模型总结 生产者消费者模型什么时候用? 1.程序中有两类角色 一类负责生产数据(生产者) 一类负责处理数据(消费者) 2.引入生产者消费者模型为了解决的问题是 平衡生产者与消费者之间的速度 ...

  2. python 之 并发编程(生产者消费者模型、守护进程的应用)

    9.8 生产者消费者模型 该模型中包含两类重要的角色: 1.生产者:将负责造数据的任务比喻为生产者 2.消费者:接收生产者造出的数据来做进一步的处理的被比喻成消费者 实现生产者消费者模型三要素:1.生 ...

  3. day34 并发编程之生产者消费者模型 队列

    1.守护进程(了解) """ 守护进程 表示 一个进程b 守护另一个进程a 当被守护的进程a结束后 那么b也跟着结束了 就像 皇帝驾崩 妃子殉葬 应用场景 之所以开启子进 ...

  4. python 并发编程 多进程 队列目录

    python 并发编程 多进程 队列 python 并发编程 多进程 生产者消费者模型介绍 python 并发编程 多进程 生产者消费者模型总结 python 并发编程 多进程 JoinableQue ...

  5. python并发编程&多进程(二)

    前导理论知识见:python并发编程&多进程(一) 一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_cou ...

  6. Python并发编程-多进程

    Python并发编程-多进程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.多进程相关概念 由于Python的GIL全局解释器锁存在,多线程未必是CPU密集型程序的好的选择. ...

  7. python 并发编程 多进程 目录

    python multiprocessing模块 介绍 python 开启进程两种方法 python 并发编程 查看进程的id pid与父进程id ppid python 并发编程 多进程 Proce ...

  8. python并发编程&多进程(一)

    本篇理论居多,实际操作见:  python并发编程&多进程(二) 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行) ...

  9. python 并发编程 多进程 互斥锁 目录

    python 并发编程 多进程 互斥锁 模拟抢票 互斥锁与join区别

随机推荐

  1. JAVA笔记4-static关键字

    1.static方法中不能使用this关键字 2.例题:static成员变量用于计数     

  2. 【leetcode】1239. Maximum Length of a Concatenated String with Unique Characters

    题目如下: Given an array of strings arr. String s is a concatenation of a sub-sequence of arr which have ...

  3. 数组遍历 forEach 方法

    数组的遍历 遍历数组,将数组中的所有元素都取出来. 使用for 循环执行数组的索引(length-1)相同的次数. var arr=["1", "5", &qu ...

  4. css3之3D 旋转立方体与哆啦A梦

    主要记录两个css3 3D转换的示例   ㈠哆啦A梦 三个哆啦A梦的图片,分别让其围绕X轴,Y轴,Z轴旋转60度,鼠标放上开始发生变化. 具体代码如下图所示: <!DOCTYPE html> ...

  5. [HG]腿部挂件 题解

    前言 暴力跑的比正解快. 以下暴力(循环展开+fread读入输出优化) #include<cstdio> #pragma GCC optimize(3, "Ofast" ...

  6. 【CF963C】Cutting Rectangle(数论,构造,map)

    题意: 思路:考虑构造最小的单位矩形然后平铺 单位矩形中每种矩形的数量可以根据比例算出来,为c[i]/d,其中d是所有c[i]的gcd,如果能构造成功答案即为d的因子个数 考虑如果要将两种矩形放在同一 ...

  7. [转载]深入理解iostat

    深入理解iostat 前言 iostat算是比较重要的查看块设备运行状态的工具,相信大多数使用Linux的同学都用过这个工具,或者听说过这个工具.但是对于这个工具,引起的误解也是最多的,大多数人对这个 ...

  8. webdriver驱动火狐浏览器报错:Unable to find a matching set of capabilities

    raise exception_class(message, screen, stacktrace)selenium.common.exceptions.SessionNotCreatedExcept ...

  9. 微信小程序-获取当前位置

    在 app.json 里面增加 permission 属性配置(小游戏需在game.json中配置): "permission": { "scope.userLocati ...

  10. xshell上windows和linux互传文件命令

    1.安装lrzsz包: yum install -y lrzsz 2.从windows上传文件到linux服务器: rz 会弹出选择文件窗口,按照提示做就行3.从linux服务器下载文件到本地的win ...