一 生产者消费者模型介绍

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

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

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

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

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. 搭建web服务器---Apache服务器

    一.安装Apache 尽管xampp appserv等提供了方便的集成环境,但实际上部署环境还是下载单独安装的Apache,以避免那些安全问题 二.加载php解析模块,并指定模块处理文件的类型 编辑h ...

  2. 【leetcode】1248. Count Number of Nice Subarrays

    题目如下: Given an array of integers nums and an integer k. A subarray is called nice if there are k odd ...

  3. RSA加密算法原理及RES签名算法简介(转载)

    第一部分:RSA算法原理与加密解密 一.RSA加密过程简述 A和B进行加密通信时,B首先要生成一对密钥.一个是公钥,给A,B自己持有私钥.A使用B的公钥加密要加密发送的内容,然后B在通过自己的私钥解密 ...

  4. jquery radio选择器 语法

    jquery radio选择器 语法 作用::radio 选择器选取类型为 radio 的 <input> 元素.大理石平台价格表 语法:$(":radio") jqu ...

  5. Confluence 6 文件

    通过将你的文件上传到 Confluence 能够让你在一个统一的地方分享你项目小组的 PDF 文件,Office 文档,图片以及更多的内容. 自动版本,即时预览,权限控制和全文搜索意味着在网络驱动器上 ...

  6. 分区间统计sql、删除重复数据

    删除重复数据 备份表 删除最早的评论

  7. Codeforces 343D Water Tree & 树链剖分教程

    原题链接 题目大意 给定一棵根为1,初始时所有节点值为0的树,进行以下三个操作: 将以某点为根的子树节点值都变为1 将某个节点及其祖先的值都变为0 *询问某个节点的值 解题思路 这是一道裸的树链剖分题 ...

  8. MiracleSnow网页设计HTML5+CSS3+JS全套视频教程

    终于把这套课程讲完了,虽然时间隔了很长,但也算有始有终了,这是在YY讲课中我自己录的,讲了网页设计的基础,这也是我第一次给那么多人讲课,讲的不好多多包涵. 前几次视频和课件是分开的,后几次都打包在一起 ...

  9. python学习之路(2)(渗透信息收集)

    scapy的用法 通过目标ip的回复判断目标ip主机的情况 先写上三层的IP 四层的TCP 然后r.display看一下我们的包 src是源ip dst是目标ip 我们添加目标ip 这里是网关的ip ...

  10. 安装OpenCV 3 on Raspbian Jessie

    环境: 硬件:树莓派三代B型, 5MP Camera Board Module 软件:Raspbian,Opencv 安装依赖 $ sudo apt-get update   $ sudo apt-g ...