理解生产者消费者模型及在Python编程中的运用实例

 更新时间:2016年06月26日 14:52:10   作者:j_hao104   我要评论
生产者消费者模型一般用于体现程序的多线程并发性,Python的多线程虽然受到GIL控制,但依然可以构建队列来简单体现出模型的思路,这里我们就来共同理解生产者消费者模型及在Python编程中的运用实例:

什么是生产者消费者模型

在 工作中,大家可能会碰到这样一种情况:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产 生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。在生产者与消费者之间在加个缓冲区,我们形象的称之为仓库,生产者负责往仓库了进商 品,而消费者负责从仓库里拿商品,这就构成了生产者消费者模型。结构图如下:

2016626144908200.jpg (401×74)

生产者消费者模型的优点:

1、解耦

假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化, 可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。

举个例子,我们去邮局投递信件,如果不使用邮筒(也就是缓冲区),你必须得把信直接交给邮递员。有同学会说,直接给邮递员不是挺简单的嘛?其实不简单,你必须 得认识谁是邮递员,才能把信给他(光凭身上穿的制服,万一有人假冒,就惨了)。这就产生和你和邮递员之间的依赖(相当于生产者和消费者的强耦合)。万一哪天邮递员换人了,你还要重新认识一下(相当于消费者变化导致修改生产者代码)。而邮筒相对来说比较固定,你依赖它的成本就比较低(相当于和缓冲区之间的弱耦合)。

2、支持并发

由于生产者与消费者是两个独立的并发体,他们之间是用缓冲区作为桥梁连接,生产者只需要往缓冲区里丢数据,就可以继续生产下一个数据,而消费者只需要从缓冲区了拿数据即可,这样就不会因为彼此的处理速度而发生阻塞。

接上面的例子,如果我们不使用邮筒,我们就得在邮局等邮递员,直到他回来,我们把信件交给他,这期间我们啥事儿都不能干(也就是生产者阻塞),或者邮递员得挨家挨户问,谁要寄信(相当于消费者轮询)。

3、支持忙闲不均

缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。 等生产者的制造速度慢下来,消费者再慢慢处理掉。

为了充分复用,我们再拿寄信的例子来说事。假设邮递员一次只能带走1000封信。万一某次碰上情人节(也可能是圣诞节)送贺卡,需要寄出去的信超过1000封,这时 候邮筒这个缓冲区就派上用场了。邮递员把来不及带走的信暂存在邮筒中,等下次过来 时再拿走。

Python示例:
利用队列实现简单的生产者消费者模型,生产者产生时间放入队列,消费者取出时间打印

class Consumer(threading.Thread):
  def __init__(self, queue):
    threading.Thread.__init__(self)
    self._queue = queue
  def run(self):
    while True:
      msg = self._queue.get()
      if isinstance(msg, str) and msg == 'quit':
        break
      print "I'm a thread, and I received %s!!" % msg
    print 'Bye byes!'

def producer():
  queue = Queue.Queue()
  worker = Consumer(queue)
  worker.start() # 开启消费者线程
  start_time = time.time()
  while time.time() - start_time < 5:
    queue.put('something at %s' % time.time())
    time.sleep(1)
  queue.put('quit')
  worker.join()

if __name__ == '__main__':
  producer()

   
使用多线程,在做爬虫的时候,生产者用着产生url链接,消费者用于获取url数据,在队列的帮助下可以使用多线程加快爬虫速度。

import time
import threading
import Queue
import urllib2
class Consumer(threading.Thread):
  def __init__(self, queue):
    threading.Thread.__init__(self)
    self._queue = queue
  def run(self):
    while True:
      content = self._queue.get()
      print content
      if isinstance(content, str) and content == 'quit':
        break
      response = urllib2.urlopen(content)
    print 'Bye byes!'

def Producer():
  urls = [
    'http://211.103.242.133:8080/Disease/Details.aspx?id=2258',
    'http://211.103.242.133:8080/Disease/Details.aspx?id=2258',
    'http://211.103.242.133:8080/Disease/Details.aspx?id=2258',
    'http://211.103.242.133:8080/Disease/Details.aspx?id=2258'
  ]
  queue = Queue.Queue()
  worker_threads = build_worker_pool(queue, 4)
  start_time = time.time()
  for url in urls:
    queue.put(url)
  for worker in worker_threads:
    queue.put('quit')
  for worker in worker_threads:
    worker.join()
  print 'Done! Time taken: {}'.format(time.time() - start_time)

def build_worker_pool(queue, size):
  workers = []
  for _ in range(size):
    worker = Consumer(queue)
    worker.start()
    workers.append(worker)
  return workers
if __name__ == '__main__':
  Producer()

相关文章

  • 非递归的输出1-N的全排列实例(推荐)

    非递归的输出1-N的全排列实例(推荐)

    下面小编就为大家带来一篇非递归的输出1-N的全排列实例(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • 使用django的ORM框架按月近一年内的数据方法

    使用django的ORM框架按月近一年内的数据方法

    今天小编就为大家分享一篇使用django的ORM框架按月近一年内的数据方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • 利用python爬取斗鱼app中照片方法实例

    利用python爬取斗鱼app中照片方法实例

    最近在学习python,通过实践是学习的一个好办法,下面这篇文章就来给大家介绍了关于利用python爬取斗鱼app中照片的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友下面来一起看看吧。
    2017-12-12
  • Python Numpy计算各类距离的方法

    Python Numpy计算各类距离的方法

    这篇文章主要介绍了Python Numpy计算各类距离的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • Python multiprocessing模块中的Pipe管道使用实例

    Python multiprocessing模块中的Pipe管道使用实例

    这篇文章主要介绍了Python multiprocessing模块中的Pipe管道使用实例,本文直接给出使用实例,需要的朋友可以参考下
    2015-04-04
  • python生成随机红包的实例写法

    python生成随机红包的实例写法

    在本篇文章里小编给大家整理的是关于python生成随机红包的实例写法以及相关知识点,有需要的朋友们可以学习下。
    2019-09-09
  • Python实现提取文章摘要的方法

    Python实现提取文章摘要的方法

    这篇文章主要介绍了Python实现提取文章摘要的方法,实例分析了Python提取文章摘要的原理与实现技巧,需要的朋友可以参考下
    2015-04-04
  • Python3实现计算两个数组的交集算法示例

    Python3实现计算两个数组的交集算法示例

    这篇文章主要介绍了Python3实现计算两个数组的交集算法,结合2个实例形式总结分析了Python3针对数组的遍历、位运算以及元素的添加、删除等相关操作技巧,需要的朋友可以参考下
    2019-04-04
  • CentOS7下python3.7.0安装教程

    CentOS7下python3.7.0安装教程

    这篇文章主要为大家详细介绍了CentOS7下python3.7.0安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • Python轻量级ORM框架Peewee访问sqlite金沙国际官网的方法详解

    Python轻量级ORM框架Peewee访问sqlite金沙国际官网的方法详解

    这篇文章主要介绍了Python轻量级ORM框架Peewee访问sqlite金沙国际官网的方法,结合实例形式较为详细的分析了ORM框架的概念、功能及peewee的安装、使用及操作sqlite金沙国际官网的方法,需要的朋友可以参考下
    2017-07-07

最新评论