一 生产者消费者模型介绍

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

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

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

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

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. "TypeError: handler.call is not a function"问题

    进入组件页面时,vue报错:Error in mounted hook: "TypeError: handler.call is not a function", 造成报错原因就是 ...

  2. Documents.Open返回值为null

    上个月出现的一个问题,将解决方法记录一下~ [问题]无法通过SAP系统外部OS命令(SM69)执行OS服务器上Powershell文件对Office文档的相关命令操作(打开文档等命令). [现象]执行 ...

  3. python selenium 笔记

    1.安装环境  下载python 3.6.4 第一页把最下面的环境变量勾上.第二页把 all user  勾上  直接安装到下一步 安装完成之后 cmd直接输入python  可以看到版本 2.安装  ...

  4. 3、Grid、GridSplitter 网格分离器、SharedSizeGroup 共享尺寸组

    Grid——网格布局,是WPF中最强大的布局容器,可以实现任何其他容器的布局.一个网格中只展示一个元素,若要展示多元素,可用容器 布局舍入:网格的边界有时会模糊,如三等分100宽度无法被整除.推荐设定 ...

  5. jquery enabled选择器 语法

    jquery enabled选择器 语法 作用::enabled 选择器选取所有启用的表单元素.大理石平台精度等级 语法:$(":enabled") jquery enabled选 ...

  6. 《剑指offer》算法题第四天

    今日题目: 二进制中1的个数 数值的整数次方 调整数组顺序使奇数位于偶数前面 链表中倒数第K个节点 链表中环的入口节点 今天的题目都比较简单,但是前三道题都有不同的解法,4,5两题就不在这边讨论了,其 ...

  7. B/S结构下上传下载大文件(1G以上)的解决方案

    以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传  ...

  8. CF293E Close Vertices 点分治+树状数组

    开始zz写了一个主席树,后来发现写个树状数组就行~ #include <cstdio> #include <vector> #include <algorithm> ...

  9. BZOJ 3732: Network Kruskal 重构树

    模板题,练练手~ Code: #include <cstdio> #include <algorithm> #define N 80000 #define setIO(s) f ...

  10. Java-Thread 线程

    一.进程与线程的概念 进程和线程都是一个CPU工作时间段的描述,只是关注点不同. 进程(Process): 资源(CPU,内存等,文件,网络等)分配的基本单位.系统中有很多进程,它们都会使用内存.为了 ...