一 生产者消费者模型介绍

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

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

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

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

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. [CF1105E] Helping Hiaset

    问题描述 你在某社交网站上面注册了一个新账号,这个账号有\(n(n\leq 10^5)\)次记录.要么就是你更改过一次ID,要么就是一个ID为\(s(|s|\leq 40)\)的朋友访问过你的空间. ...

  2. vue项目搭建步骤以及一些安装依赖包

    一. vue-cli初始化1. 全局安装 vue-clinpm install --global vue-cli2. 创建一个基于 webpack 模板的新项目vue init webpack my- ...

  3. Python 正则表达式Ⅲ

    re.match与re.search的区别 re.match只匹配字符串的开始,如果字符串开始https://www.xuanhe.net/不符合正则表达式,则匹配失败,函数返回None:而re.se ...

  4. MySQL数据库中的索引(一)——索引实现原理

    今天我们来探讨一下数据库中一个很重要的概念:索引. MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构,即索引是一种数据结构. 我们知道,数据库查询是数据库的最主要 ...

  5. BZOJ 3173: [Tjoi2013]最长上升子序列 Splay

    一眼切~ 重点是按照 $1$~$n$ 的顺序插入每一个数,这样的话就简单了. #include <cstdio> #include <algorithm> #define N ...

  6. PyCharm中Qt Designer+PyUIC配置

    本文环境配置: 系统=>windows10:64位 语言=>Python:3.7.1 第三方库PyQT5:5.11.3pyqt5-tools:5.11.3.1.4 工具=>PyCha ...

  7. Hibernate与MyBaits的区别?

    (1)Hibernate是全自动,而myBatis是半自动,Hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成SQL.而myBat ...

  8. python 判断是字母的多种方法

    方法一:isalpha() "a".isalpha()   方法二:string.letters string.uppercase  import string  s=" ...

  9. hibernate注意

    1.设置id <id name="ID"> <!-- ????????????????? --> <generator class="ide ...

  10. c#协变 抗变

    public class Fa : TranOut<Fa>, TranIn<Fa> { } public class son : Fa, TranOut<son>, ...