zoukankan      html  css  js  c++  java
  • 生产者消费者模型

    生产者消费者模型

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

    生产者:泛指产生数据的一方

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

    用来解决什么问题

    • 案例
      • 食堂饭店就是生产者
      • 我们就是消费者

    假设厨师只有一个盘子,那么在他做菜的时候,我们就需要等,而我们吃饭的时候,他也需要等

    导致效率低,双方相互等待,因为双方的效率不一致

    具体的解决方案:

    1. 先将双方的耦合解开,让不同的进程去负责不同的任务
    2. 提供一个共享的容器,来平衡双方的能力,双方只要使用这个容器就可以了。推荐使用队列,因为队列可以在进程间共享内存

    例如:

    from multiprocessing import Process, Queue
    import requests, re, time, random, os
    
    def product(urls, q):
        '''生产者,爬取数据'''
        for ind, url in enumerate(urls):
            response = requests.get(url)
            response.encoding = response.apparent_encoding
            q.put(response.text)
            print(f'第{ind+1}个网站,爬取状态为{response.status_code},进程编号{os.getpid()}')
    
    
    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%s个编码信息" % (i, len(res), len(text)))
    
    
    if __name__ == '__main__':
        urls = [
            'http://www.baidu.com',
            'http://www.jd.com',
            'http://www.taobao.com',
        ]
        q = Queue()
        p = Process(target=product, args=(urls, q))
        p.start()
    
        c = Process(target=customer, args=(q,))
        c.start()
    
    
    第1个网站,爬取状态为200,进程编号1672
    第1个任务获取到1个img2287个编码信息
    第2个网站,爬取状态为200,进程编号1672
    第2个任务获取到0个img90221个编码信息
    第3个网站,爬取状态为200,进程编号1672
    第3个任务获取到0个img141513个编码信息
    ...
    

    但是这样做有一个问题,消费者不知道什么时候结束

    如果生产者只有一个,那么可以在生产结束后往q中put一个None,作为生产结束的标识,但是但生产者有多个的时候,这种方法就不可行了

    JoinableQueue

    • 继承自Queue,用法一致
    • 新增了join(等待) 和task_done(任务完成)

    其中join是一个阻塞函数,会一直阻塞到task_done的调用次数等于存入元素的个数才会释放,用于表示队列任务处理完成

    案例:

    from multiprocessing import Process, JoinableQueue
    import time, random
     '''如何判定今天的热狗真的吃完了
     	1.确定生成者任务完成
     	2.确定生出来的数据已经全部处理完成'''
    
    # 生产热狗
    def product(q, name):
        for i in range(3):
            dog = f"{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()  # 也可以直接终止消费者进程
       
    

    各种各样的队列(如redis消息队列,MQ消息队列)都是典型的消费者生产者模型。

    主要用于流量的削峰,保证服务器不会因为高并发而崩溃

  • 相关阅读:
    vc++ 错误 CreateWindow
    设置某个页面的编码方式
    部署Struts2框架
    oracle之约束
    java web开发(三)、Ajax技术
    vs2008 安装出错 Microsoft Visual Studio Web 组件安装失败
    java web开发(二)、Servlet技术
    WLS Zip Distribution for Oracle WebLogic Server 12.1.1.0安装
    MyEclipse配置Weblogic服务器
    js 未结束的字符串常量错误解决方法
  • 原文地址:https://www.cnblogs.com/lucky75/p/11134837.html
Copyright © 2011-2022 走看看