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

    生产者消费者模型

    生产者消费者模型

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

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

    案例:

    食堂饭店就是生产者,负责做饭
    
    负责吃饭的就是消费者
    

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

    问题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 消息队列

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

  • 相关阅读:
    ArcGIS 10.1 如何连接数据库(转载)
    silverlight generic.xaml 包含中文 编译错误的问题
    WPF XAML之bing使用StringFormat (转)
    geoserver 知识小计
    [100天计划][1/15][1/30]开篇清单
    工作总结,给个公式,发发牢骚,继续得过
    值类型与引用类型(特殊的string) Typeof和GetType() 静态和非静态使用 参数传递 相关知识
    跑步之后的胡思乱想
    Linq To DataSet
    近期专案PM相关收获
  • 原文地址:https://www.cnblogs.com/Hades123/p/11153442.html
Copyright © 2011-2022 走看看