生产者消费者模型

生产者消费者模型

生产者消费者模型

模型就是解决某个固定问题的方法或者套路

  • 生产者:泛指产生数据的一方
  • 消费者:泛指处理数据的一方

案例:

食堂饭店就是生产者,负责做饭

负责吃饭的就是消费者

那我们来想一想,这两者之间是否有什么问题,我需要做到的是做饭的和吃饭的能够做到无缝衔接,也就是饭店刚做好饭,刚好吃饭的来了?

问题1:饭店不知道什么时候吃饭的回来

问题2:吃饭的不知道饭店什么时候做好饭

这样一来,就会造成效率低,因为双方的处理速度不同,一个块一个慢,则双方需要相互等待

解决办法

  1. 先将双方解开耦合,让不同的进程负责不同的任务
  2. 提供一个共享的容器来平衡双方的能力,可以使用队列
from multiprocessing import Process,Queue
import requests
import re,os,time,random


# 生产者任务
def product(urls,q):
    i = 0
    for url in urls:
        response = requests.get(url)
        text = response.text
        # 将生产完成的数据放入队列中
        time.sleep(random.random())
        q.put(text)
        i += 1
        print(os.getpid(),"生产了第%s个数据" % i)


def customer(q):
    i = 0
    while True:
        text = q.get()
        time.sleep(random.random())
        res = re.findall('src=//(.*?) width', text)
        i += 1
        print(" 第%s个任务获取到%s个img" % (i,len(res)))

        
if __name__ == '__main__':
    urls = [
        "http://www.baidu.com",
        "http://www.baidu.com",
        "http://www.baidu.com",
        "http://www.baidu.com",
    ]

    # 创建一个双方能共享的容器
    q = Queue()

    # 生产者进程
    p1 = Process(target=product,args=(urls,q))
    p1.start()


    # 消费者进程
    c = Process(target=customer,args=(q,))
    c.start()
    
    '''
    42848 生产了第1个数据
    42848 生产了第2个数据
     第1个任务获取到1个img
    42848 生产了第3个数据
     第2个任务获取到1个img
    42848 生产了第4个数据
     第3个任务获取到1个img
     第4个任务获取到1个img
    '''

问题来了:消费者啥时候结束呢

JoinableQueue

JoinableQueue继承自Queue,与Queue的用法一致,在Queue的基础上,增加了join和task_down两个方法

join是一个阻塞函数,会阻塞到task_down调用次数和存入的元素数量一致时,可以用于表示队列任务处理完成

from multiprocessing import Process,JoinableQueue
import time,random

"""
生产者 负责生产热狗 
消费者 负责吃热狗  
"""

# 生产者任务
def product(q,name):
    for i in range(5):
        dog = "%s的热狗%s" % (name,(i + 1))
        time.sleep(random.random())
        print("生产了",dog)
        q.put(dog)

# 吃热狗
def customer(q):
    while True:
        dog = q.get()
        time.sleep(random.random())
        print("消费了%s" % dog)
        q.task_done() # 标记这个任务处理完成

        
if __name__ == '__main__':

    # 创建一个双方能共享的容器
    q = JoinableQueue()

    # 生产者进程
    p1 = Process(target=product,args=(q,"上海分店"))
    p2 = Process(target=product,args=(q,"北京分店"))

    p1.start()
    p2.start()


    # 消费者进程
    c = Process(target=customer,args=(q,))
    # c.daemon = True # 可以将消费者设置为守护进程 当主进程确认 任务全部完成时 可以随着主进程一起结束
    c.start()


    p1.join()
    p2.join()  # 代码走到这里意味着生产方完成

    q.join() # 意味着队列中的任务都处理完成了

    # 结束所有任务
    c.terminate() # 直接终止消费者进程
  • 扩展
  1. redis 消息队列
  2. MQ 消息队列

常用来做流量削峰,保证服务器不会因为高并发而发生奔溃

posted @ 2019-07-08 20:03  蔚蓝的爱  阅读(158)  评论(0编辑  收藏  举报