python多进程下的生产者和消费者模型


Posted in Python onMay 07, 2020

一、生产者消费者模型介绍

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

生产者是指生产数据的任务,消费者是指消费数据的任务。当生产者的生产能力远大于消费者的消费能力,生产者就需要等消费者消费完才能继续生产新的数据,同理,如果消费者的消费能力远大于生产者的生产能力,消费者就需要等生产者生产完数据才能继续消费,这种等待会造成效率的低下,为了解决这种问题就引入了生产者消费者模型。

1.2 如何实现生产者消费者模型

进程间引入队列可以实现生产者消费者模型,通过使用队列无需考虑锁的概念,因为进程间的通信是通过队列来实现的;

生产者生产的数据往队列里面写,消费者消费数据直接从队列里面取,这样就对实现了生产者和消费者之间的解耦。

生产者 -- >  队列  <--消费者

二、Queue实现生产者消费者模型

2.1 消费者生产者模型代码

from multiprocessing import Process, Queue
import time
 
# 消费者方法
def consumer(q, name):
  while True:
    res = q.get()
    # if res is None: break
    print("%s 吃了 %s" % (name, res))
 
# 生产者方法
def producer(q, name, food):
  for i in range(3):
    time.sleep(1) # 模拟生产西瓜的时间延迟
    res = "%s %s" % (food, i)
    print("%s 生产了 %s" % (name, res))
    # 把生产的vegetable放入到队列中
    q.put(res)
 
if __name__ == "__main__":
  #创建队列
  q = Queue()
  # 创建生产者
  p1 = Process(target=producer, args=(q, "kelly", "西瓜"))
  c1 = Process(target=consumer, args=(q, "peter",))
  p1.start()
  c1.start()
 
  # p1.join()
  # q.put(None)
  print("主进程")

2.2 执行结果

2.2.1 直接执行上面的代码的结果

直接执行会出现一个问题就是生产者生产完了,没有向消费者发送一个停止的信号,所以消费者一直会一直阻塞在q.get(),导致程序无法退出。

python多进程下的生产者和消费者模型

为了解决上面的问题,让消费者消费完了生产者的数据之后自动退出,就需要在生产者进程介绍的时候往队列里面put一个结束信号,消费者拿到这个信号,就退出消费进程。

主要是两个地方修改 ,把下方代码的注释打开就可以实现消费者消费完接收到生产者的结束信号就退出消费者进程了。

def consumer():
  if res is None: break
 
if __name__ == "__main__":
p1.join() 
q.put(None)

2.2.2 把注释打开后的运行结果

把注释打开后,消费者拿到了生产者发送的结束信号,可以正常退出程序了。

python多进程下的生产者和消费者模型

但如果有n个消费者,就需要发送n个结束信号,这种方式就不是那么简洁,像下面的代码这样:

from multiprocessing import Process, Queue
import time
 
 
# 消费者方法
def consumer(q, name):
  while True:
    res = q.get()
    if res is None: break
    print("%s 吃了 %s" % (name, res))
 
 
# 生产者方法
def producer(q, name, food):
  for i in range(3):
    time.sleep(1) # 模拟生产西瓜的时间延迟
    res = "%s %s" % (food, i)
    print("%s 生产了 %s" % (name, res))
    # 把生产的vegetable放入到队列中
    q.put(res)
 
 
if __name__ == "__main__":
  # 创建队列
  q = Queue()
  # 创建生产者
  p1 = Process(target=producer, args=(q, "kelly", "西瓜"))
  p2 = Process(target=producer, args=(q, "kelly2", "香蕉"))
  c1 = Process(target=consumer, args=(q, "peter",))
  c2 = Process(target=consumer, args=(q, "peter2",))
  c3 = Process(target=consumer, args=(q, "peter3",))
  p1.start()
  p2.start()
  c1.start()
  c2.start()
  c3.start()
 
  p1.join()
  p2.join()
  q.put(None)
  q.put(None)
  q.put(None)
  print("主进程")

其实我们现在就是生产者生产完数据之后想往队列里面发送一个结束信号,python语言提供了另外一种队列JoinableQueue([maxsize])来解决这种问题

三、JoinableQueue实现生产者消费者模型

3.1 JoinableQueue方法介绍

JoinableQueue([maxsize]) : A queue type which also supports join() and task_done() methods

q.task_done():消费者使用此方法发出信号,表示q.get()的返回项目已经被处理。

q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理;阻塞将持续到队列中的每个项目均调用q.task_done()方法为止。

3.2 JoinableQueue实现生产者消费者模型源码

from multiprocessing import Process,JoinableQueue
import time
 
 
# 消费者方法
def consumer(q, name):
  while True:
    res = q.get()
    if res is None: break
    print("%s 吃了 %s" % (name, res))
    q.task_done() # 发送信号给q.join(),表示已经从队列中取走一个值并处理完毕了
 
 
# 生产者方法
def producer(q, name, food):
  for i in range(3):
    time.sleep(1) # 模拟生产西瓜的时间延迟
    res = "%s %s" % (food, i)
    print("%s 生产了 %s" % (name, res))
    # 把生产的vegetable放入到队列中
    q.put(res)
  q.join() # 等消费者把自己放入队列的所有元素取完之后才结束
 
 
if __name__ == "__main__":
  # q = Queue()
  q = JoinableQueue()
  # 创建生产者
  p1 = Process(target=producer, args=(q, "kelly", "西瓜"))
  p2 = Process(target=producer, args=(q, "kelly2", "蓝莓"))
  # 创建消费者
  c1 = Process(target=consumer, args=(q, "peter",))
  c2 = Process(target=consumer, args=(q, "peter2",))
  c3 = Process(target=consumer, args=(q, "peter3",))
 
  c1.daemon = True
  c2.daemon = True
  c3.daemon = True
 
  p_l = [p1, p2, c1, c2, c3]
  for p in p_l:
    p.start()
  
  p1.join()
  p2.join()
  # 1.主进程等待p1,p2进程结束才继续执行
  # 2.由于q.join()的存在,生产者只有等队列中的元素被消费完才会结束
  # 3.生产者结束了,就代表消费者已经消费完了,也可以结束了,所以可以把消费者设置为守护进程(随着主进程的退出而退出)
 
  print("主进程")

3.3 运行结果

通过运行结果可以看出,生产者没有手动发送结束信号给消费者,而是通过JoinableQueue队列的方式也实现了生产者消费者模型。

python多进程下的生产者和消费者模型

到此这篇关于python多进程下的生产者和消费者模型的文章就介绍到这了,更多相关python多进程下的生产者和消费者内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
使用python获取CPU和内存信息的思路与实现(linux系统)
Jan 03 Python
简介二分查找算法与相关的Python实现示例
Aug 26 Python
python 调用c语言函数的方法
Sep 29 Python
使用python编写简单的小程序编译成exe跑在win10上
Jan 15 Python
浅谈Python traceback的优雅处理
Aug 31 Python
浅谈Python大神都是这样处理XML文件的
May 31 Python
python实现windows倒计时锁屏功能
Jul 30 Python
python中sort和sorted排序的实例方法
Aug 26 Python
python判断无向图环是否存在的示例
Nov 22 Python
使用anaconda安装pytorch的实现步骤
Sep 03 Python
python与js主要区别点总结
Sep 13 Python
Python list和str互转的实现示例
Nov 16 Python
基于python实现检索标记敏感词并输出
May 07 #Python
Python3自动生成MySQL数据字典的markdown文本的实现
May 07 #Python
如何搭建pytorch环境的方法步骤
May 06 #Python
Python基于Tkinter编写crc校验工具
May 06 #Python
使用Python实现批量ping操作方法
May 06 #Python
Python super()函数使用及多重继承
May 06 #Python
python中shell执行知识点
May 06 #Python
You might like
linux php mysql数据库备份实现代码
2009/03/10 PHP
PHP 透明水印生成代码
2012/08/27 PHP
PHP5中Cookie与 Session使用详解
2013/04/30 PHP
php mysql_list_dbs()函数用法示例
2017/03/29 PHP
top.location.href 没有权限 解决方法
2008/08/05 Javascript
JavaScript asp.net 获取当前超链接中的文本
2009/04/14 Javascript
分享XmlHttpRequest调用Webservice的一点心得
2012/07/20 Javascript
SeaJS 与 RequireJS 的差异对比
2014/12/08 Javascript
jQuery中:submit选择器用法实例
2015/01/03 Javascript
javascript结合fileReader 实现上传图片
2015/01/30 Javascript
jQuery实现表格颜色交替显示的方法
2015/03/09 Javascript
js+html5实现canvas绘制镂空字体文本的方法
2015/06/05 Javascript
浅谈JavaScript 浏览器对象
2016/06/03 Javascript
Mac系统下Webstorm快捷键整理大全
2017/05/28 Javascript
JavaScript ES6中const、let与var的对比详解
2017/06/18 Javascript
vue.js路由跳转详解
2017/08/28 Javascript
js的函数的按值传递参数(实例讲解)
2017/11/16 Javascript
EasyUI的DataGrid绑定Json数据源的示例代码
2017/12/16 Javascript
vue iview实现动态路由和权限验证功能
2018/04/17 Javascript
layer.confirm()右边按钮实现href的例子
2019/09/27 Javascript
Vue 设置axios请求格式为form-data的操作步骤
2019/10/29 Javascript
浅谈JavaScript中的“!!”作用
2020/08/03 Javascript
python冒泡排序简单实现方法
2015/07/09 Python
Python使用pymongo库操作MongoDB数据库的方法实例
2019/02/22 Python
使用python实现滑动验证码功能
2019/08/05 Python
详解Django-channels 实现WebSocket实例
2019/08/22 Python
基于python判断目录或者文件代码实例
2019/11/29 Python
python编写一个会算账的脚本的示例代码
2020/06/02 Python
Pyecharts 中Geo函数常用参数的用法说明
2021/02/01 Python
canvas里面如何基于随机点绘制一个多边形的方法
2018/06/13 HTML / CSS
国家励志奖学金获奖感言
2014/01/09 职场文书
高中生自我评语大全
2014/01/19 职场文书
教师师德演讲稿
2014/05/06 职场文书
教师作风整顿个人剖析材料
2014/10/10 职场文书
幼儿园教师节感谢信
2015/01/23 职场文书
SQL语法CONSTRAINT约束操作详情
2022/01/18 MySQL