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

    生产者消费者模型

    假设有一个公共队列,生产者向队列中写数据,消费者从队列中读数据。当队列中没有任何数据的时候,消费者应该停止运行并等待(wait),而不是继续尝试读取数据而引发读取空队列的异常。而当生产者在队列中加入数据之后,应该有一个渠道去告诉(notify)消费者。然后消费者可以再次从队列中进行读取,而IndexError不再出现。

    from threading import Thread
    import time
    import random
    from queue import Queue
    
    # 创建一个队列对象
    queue = Queue(10)
    
    # 定义一个生产者类,并继承线程类
    class ProducerThread(Thread):
        # 定义自己的run
        def run(self):
            nums = range(5)
            global queue
            while True:
                num = random.choice(nums)
                # 向队列中put一个值
                queue.put(num)
                print("Produced", num)
                # 睡眠时间,随机1秒之内
                time.sleep(random.random())
    
    # 创建一个消费者类,并继承线程类
    class ConsumerThread(Thread):
        # 重新定义run方法
        def run(self):
            # 将队列全局化
            global queue
            while True:
                # 从队列中get值
                num = queue.get()
                # 一个任务完成
                queue.task_done()
                print("Consumed", num)
                # 睡眠时间,随机1秒之内
                time.sleep(random.random())
    
    ProducerThread().start()
    ConsumerThread().start()

    ----------------执行结果-----------------

    Produced 1
    Consumed-----------> 1
    Produced 3
    Consumed-----------> 3
    Produced 1
    Produced 0
    Consumed-----------> 1
    Consumed-----------> 0
    Produced 0

    解释:

    • 使用Queue实例(下称队列)。
    • 这个队列有一个condition,它有自己的lock。如果你使用Queue,你不需要为condition和lock而烦恼。
    • 生产者调用队列的put方法来插入数据。
    • put()在插入数据前有一个获取lock的逻辑。
    • 同时,put()也会检查队列是否已满。如果已满,它会在内部调用wait(),生产者开始等待。
    • 消费者使用get方法。
    • get()从队列中移出数据前会获取lock。
    • get()会检查队列是否为空,如果为空,消费者进入等待状态。
    • get()和put()都有适当的notify()。现在就去看Queue的源码吧。
    import threading
    import time
    import random
    from threading import Condition
    
    queues = []
    MAX_NUM = 10
    condition = Condition()
    
    class ProducerThread(threading.Thread):
        def run(self):
            nums = range(5)
            global queues
            while True:
                condition.acquire()
                if len(queues) == MAX_NUM:
                    print('queues full, producer is waithing!')
                    condition.wait()
                    print('space in queue, consumer notified the producer')
                num = random.choice(nums)
                queues.append(num)
                print('Producer', num)
                condition.notify()
                condition.release()
                time.sleep(random.random())
    
    class ConsumerThread(threading.Thread):
        def run(self):
            global queues
            while True:
                condition.acquire()
                if not queues:
                    print('nothing in queue, consumer is waithing')
                    condition.wait()
                    print('producer added something to queue and notified the consumer')
                num = queues.pop(0)
                print('consumed--------------->', num)
                condition.release()
                time.sleep(random.random())
    
    ProducerThread().start()
    ConsumerThread().start()

    解释:

    • 对于消费者,在消费前检查队列是否为空。
    • 如果为空,调用condition实例的wait()方法。
    • 消费者进入wait(),同时释放所持有的lock。
    • 除非被notify,否则它不会运行。
    • 生产者可以acquire这个lock,因为它已经被消费者release。
    • 当调用了condition的notify()方法后,消费者被唤醒,但唤醒不意味着它可以开始运行。
    • notify()并不释放lock,调用notify()后,lock依然被生产者所持有。
    • 生产者通过condition.release()显式释放lock。
    • 消费者再次开始运行,现在它可以得到队列中的数据而不会出现IndexError异常。

    为队列增加大小限制

    生产者不能向一个满队列继续加入数据。

    它可以用以下方式来实现:

    • 在加入数据前,生产者检查队列是否为满。
    • 如果不为满,生产者可以继续正常流程。
    • 如果为满,生产者必须等待,调用condition实例的wait()。
    • 消费者可以运行。消费者消耗队列,并产生一个空余位置。
    • 然后消费者notify生产者。
    • 当消费者释放lock,消费者可以acquire这个lock然后往队列中加入数据。
  • 相关阅读:
    Java相对路径读取文件
    【转载】 OpenCV ——双线性插值(Bilinear interpolation)
    【转载】 从ACM会议看中国大陆计算机科学与国外的差距
    【转载】 一个老博士的经验顺口溜! 研究生生活的精华总结!
    【转载】 研究生生活总结(2):从技术到研究再到技术的过程
    【转载】 研究生生活总结(1):当助教的那些人和事
    【转载】 如何看待 2019 年 CS PhD 现扎堆申请且大部分为 AI 方向?未来几年 AI 泡沫会破裂吗?
    【转载】 深度强化学习处理cartpole为什么reward很难超过200?
    【转载】 强化学习中 采用 【首次访问的蒙特卡洛预测法】 的算法描述
    【转载】 混合智能
  • 原文地址:https://www.cnblogs.com/yxy-linux/p/5695741.html
Copyright © 2011-2022 走看看