一 生产者消费者模型介绍

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

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

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

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

  1. import time
  2.  
  3. def producer():
  4. '''生产者是厨师'''
  5.  
  6. for i in range(1,4): # 模拟生产三个数据
  7. res = "包子%s" % i
  8. time.sleep(2)
  9. print("生产者生产%s" % res)
  10.  
  11. consumer(res)
  12.  
  13. def consumer(res):
  14. '''消费者吃包子'''
  15.  
  16. time.sleep(1)
  17. print("消费者消费%s" % res)
  18.  
  19. if __name__ == "__main__":
  20. producer()
  21.  
  22. '''
  23. 生产者生产包子1
  24. 消费者消费包子1
  25. 生产者生产包子2
  26. 消费者消费包子2
  27. 生产者生产包子3
  28. 消费者消费包子3
  29. '''

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

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

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

+

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

二 生产者消费者模型实现

通过队列

  1. from multiprocessing import Process
  2. from multiprocessing import Queue
  3. import time
  4.  
  5. def producer(q):
  6.  
  7. for i in range(1,6):
  8. res = "包子%s" %i
  9. time.sleep(0.5)
  10. print("生产者生产%s" % res)
  11.  
  12. # 现在不是给消费者了 放入数据 res 把包子放到队列
  13. q.put(res)
  14.  
  15. def consumer(q):
  16. while True:
  17. # 一直接取数据
  18. res = q.get()
  19. time.sleep(1)
  20. print("消费者消费%s" % res)
  21.  
  22. if __name__ == "__main__":
  23.  
  24. # 容器
  25. q = Queue()
  26.  
  27. # 生产者们
  28. # 需要传参数 把生产后数据的往队列里丢
  29. p = Process(target=producer, args=(q,))
  30.  
  31. # 消费者们
  32. c = Process(target=consumer, args=(q,))
  33.  
  34. p.start()
  35. c.start()
  36. print("主")
  37.  

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


  1. 生产者生产包子1
  2. 生产者生产包子2
  3. 生产者生产包子3
  4. 消费者消费包子1
  5. 生产者生产包子4
  6. 生产者生产包子5
  7. 消费者消费包子2
  8. 消费者消费包子3
  9. 消费者消费包子4
  10. 消费者消费包子5

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

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

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

解决:

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

  1. from multiprocessing import Process
  2. from multiprocessing import Queue
  3. import time
  4.  
  5. def producer(q):
  6.  
  7. for i in range(1,6):
  8. res = "包子%s" %i
  9. time.sleep(0.5)
  10. print("生产者生产%s" % res)
  11.  
  12. # 现在不是给消费者了 放入数据 res 把包子放到队列
  13. q.put(res)
  14.  
  15. def consumer(q):
  16. while True:
  17. # 接取数据
  18. res = q.get()
  19. # 消费者在最后一次收到None后退出
  20. if res is None:break
  21. time.sleep(1)
  22. print("消费者消费%s" % res)
  23.  
  24. if __name__ == "__main__":
  25.  
  26. # 容器
  27. q = Queue()
  28.  
  29. # 生产者们
  30. # 需要传参数 把生产后数据的往队列里丢
  31. p = Process(target=producer, args=(q,))
  32.  
  33. # 消费者们
  34. c = Process(target=consumer, args=(q,))
  35.  
  36. p.start()
  37. c.start()
  38.  
  39. # 保证所有子进程执行完 主进程才能工作,不然一直阻塞
  40. p.join()
  41. # 保证生产者把所有数据扔到队列后 然后发送结束信号
  42. q.put(None)
  43. print("主")
  44.  
  45. '''
  46. 生产者生产包子1
  47. 生产者生产包子2
  48. 生产者生产包子3
  49. 消费者消费包子1
  50. 生产者生产包子4
  51. 生产者生产包子5
  52. 消费者消费包子2

  53. 消费者消费包子3
  54. 消费者消费包子4
  55. 消费者消费包子5
  56. '''

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

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

  1. from multiprocessing import Process, Queue
  2. import time
  3.  
  4. def producer(q):
  5.  
  6. for i in range(5):
  7. res = "包子%s" %i
  8. time.sleep(0.5)
  9. print("生产者生产%s" % res)
  10.  
  11. # 现在不是给消费者了 放入数据 res 把包子放到队列
  12. q.put(res)
  13.  
  14. def consumer(q):
  15. while True:
  16. # 接取数据
  17. res = q.get()
  18. if res is None:break
  19. time.sleep(1)
  20. print("消费者消费%s" % res)
  21.  
  22. if __name__ == "__main__":
  23.  
  24. # 容器
  25. q = Queue()
  26.  
  27. # 生产者们
  28. # 需要传参数 把生产后数据的往队列里丢
  29. p1 = Process(target=producer, args=(q,))
  30. p2 = Process(target=producer, args=(q,))
  31. p3= Process(target=producer, args=(q,))
  32.  
  33. # 消费者们
  34. c1 = Process(target=consumer, args=(q,))
  35. c2 = Process(target=consumer, args=(q,))
  36.  
  37. p1.start()
  38. p2.start()
  39. p3.start()
  40.  
  41. c1.start()
  42. c2.start()
  43.  
  44. # 保证所有子进程执行完 主进程才能工作,不然一直阻塞
  45. p1.join()
  46. p2.join()
  47. p3.join()
  48.  
  49. # 发完数据后 发送结束信号 有几个消费者就应该来几个信号
  50.  
  51. q.put(None)
  52. q.put(None)
  53. 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. http协议和i/o模型

    http协议----基于请求报文和响应报文完成一次http事务 应用层协议格式有两种: 文本(开发容易,但交互解析困难如http smtp),二进制(交互解析容易,但理解起来困难memocache) ...

  2. js-10s倒计时后关闭窗口

    效果: html: <h1 id="h1">10s后关闭窗口</h1> <a id="a1">启动</a> js ...

  3. CSS层定位——固定定位,相对定位,绝对定位

    主要写关于层定位的相关知识 ㈠定位概述 ⑴像图像软件中的图层一样可以对每一个layer能够精确定位操作 ⑵层定位的position属性决定了当前的一个网页元素,可以叠加到另一个网页元素上面,那么我们把 ...

  4. 在linux 下安装git

    ① 安装 Git Linux 做为服务器端系统,Windows 作为客户端系统,分别安装 Git 服务器端: #yum install -y git 安装完后,查看 Git 版本 [root@loca ...

  5. 【UOJ#129】 【NOI2015】寿司晚宴

    题目描述 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 ...

  6. Presto部署指南

    1.Presto简介说明 Presto是一个开源的分布式SQL查询引擎,适用于交互式分析查询,数据量支持GB到PB字节. Presto的设计和编写完全是为了解决像Facebook这样规模的商业数据仓库 ...

  7. D. Marcin and Training Camp

    D. Marcin and Training Camp 题目链接:http://codeforces.com/contest/1230/problem/D time limit per test: 3 ...

  8. JavaWeb_(MVC)管理员后台商品查询demo

    MVC分层实现管理员后台商品查询 MVC层即model view controller Model(模型):模型代表着核心的业务逻辑和数据(不要理解成Model只是实体类) View(视图):视图应该 ...

  9. MqttConnectReturnCode枚举值

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  10. MongoDB中的_id和ObjectId

    ObjectId是"_id"的默认类型.它设计成轻量型的,不同的机器都能用全局唯一的同种方法方便地生成它. 这是MongoDB采用ObjectId,而不是其他比较常规的做法(比如自 ...