30、Queue队列

一、Queue队列

进程彼此之间互相隔离,要实现进程间通信(IPC),则要借助于multiprocessing模块下的Queue,我们先通过下面的案例了解一下Queue的使用

from multiprocessing import Queue

if __name__ == '__main__':
    queue = Queue(3)

    queue.put('1个苹果')
    queue.put('2个苹果')
    queue.put('3个苹果')
    # queue.put('4个苹果')

    res = queue.get()
    print(res)
    res = queue.get()
    print(res)
    res = queue.get()
    print(res)
    # res = queue.get_nowait()
    # print(res)

1、方法介绍

queue = Queue(3)  # 实例化得到一个对象,括号类的数字代表队列的大小,类似一个管道最多容纳的单位,不设置大小表示默认最大

queue.put('1个苹果',)  # 对象调用的方法,用于存入一个值到队列中
# 另外put方法还有两个可选的参数block和timeout,
# block代表是否阻塞,默认值为True,如果将它改成False,队列溢出就会报错
# timeout可以指定阻塞的时间,阻塞时间结束后如果队列溢出则会报错

queue.get()  # 可以从队列读取并且删除一个元素。
# 同样,get方法也有block和timeout参数
# block为False时,get取不到值则报错
# timeout可以指定时间,在指定的时间结束后未取到值则报错

queue.put_nowait()  # 同block=False,存值溢出则报错
queue.get_nowait()  # 同block=False,取不到值则报错
    
queue.full()  # 判断队列的值是否已满,返回True和False
queue.empty()  # 判断队列的值是否为空,返回True和False
queue.qsize()  # 判断队列的值具体个数,将结果返回

二、Queue使用

1、实现进程间通信

from multiprocessing import Process, Queue
import os, time


def task(queue):
    print('进程[%s]开始放数据了' % os.getpid())
    time.sleep(2)
    queue.put('Poco is handsome')
    print('进程[%s]放完了' % os.getpid())


if __name__ == '__main__':
    queue = Queue()
    p = Process(target=task, args=(queue, ))
    p.start()

    res = queue.get()  # 会卡在这
    print(res)

2、批量生产数据放入Queue再批量取出

from multiprocessing import Process, Queue
import os


def get_task(queue):
    res = queue.get()
    print('进程【%s】取了数据:%s ' % (os.getpid(), res))


def put_task(queue):
    queue.put('进程【%s】:放了数据 ' % os.getpid())


if __name__ == '__main__':
    queue = Queue(1)
    p1 = Process(target=put_task, args=(queue,))
    p2 = Process(target=put_task, args=(queue,))
    p1.start()
    p2.start()

    p3 = Process(target=get_task, args=(queue,))
    p4 = Process(target=get_task, args=(queue,))
    p3.start()
    p4.start()

三、生产者消费者模型

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

1、基于队列实现生产者消费者模型

from multiprocessing import Process, Queue
import time, random


def producer(queue):
    # 生产的东西
    for i in range(1, 10):
        data = '厨师【黑影】,蒸了第【%s】个包子' % i
        print(data)
        time.sleep(random.randint(1, 3))  # 模拟下产包子的延迟
        queue.put('第【%s】个包子' % i)
    queue.put(None)  # 包子蒸完退出了循环,生产一个空包子代表打烊


def consumer(queue):
    while True:
        time.sleep(random.randint(1, 3))  # 模拟下吃包子的延迟
        res = queue.get()
        if not res: break  # 判断,客户取到空包子代表包子店打烊了,溜了溜了
        print('顾客【Poco】,吃下了%s' % res)


if __name__ == '__main__':
    queue = Queue()
    p1 = Process(target=producer, args=(queue,))
    p1.start()

    c1 = Process(target=consumer, args=(queue,))
    c1.start()
    
    # p1.join()  # 也可以设置一个join方法,让生产者的子进程执行完毕再执行下面的主进程
    # queue.put(None)

2、多个生产者和消费者模型

多个生产者消费者就不能用上面的“空包子”方法来实现了,因为当第一个消费者吃完空包子时程序就结束了,但有可能其他的消费者还没吃到第九个食物,所以这时候我们可以在消费者吃食物时设置一个阻塞的时间,消费者取不到食物之后报错,然后捕捉这个异常,break掉循环,程序结束

from multiprocessing import Process, Queue
import time, random


def producer(queue, cook, food):
    # 生产的东西
    for i in range(1, 10):
        data = '厨师【%s】,蒸了第【%s】个【%s】' % (cook, i, food)
        print(data)
        time.sleep(random.randint(1, 3))  # 模拟下产包子的延迟
        queue.put('第【%s】个【%s】' % (i, food))


def consumer(queue, gues):
    while True:
        try:
            res = queue.get(timeout=10)
            time.sleep(random.randint(1, 3))  # 模拟下吃包子的延迟
            print('顾客【%s】,吃下了%s' % (gues, res))
        except Exception as e:
            print(e)
            break


if __name__ == '__main__':
    queue = Queue(3)
    # 多个生产者
    p1 = Process(target=producer, args=(queue, '一乐大叔', '包子'))
    p2 = Process(target=producer, args=(queue, '山治', '窝窝头'))
    p3 = Process(target=producer, args=(queue, '小福贵', '馒头'))
    p1.start()
    p2.start()
    p3.start()
    # 多个消费者
    c1 = Process(target=consumer, args=(queue, '鸣人'))
    c2 = Process(target=consumer, args=(queue, '路飞'))
    c3 = Process(target=consumer, args=(queue, '小飞碟'))
    c1.start()
    c2.start()
    c3.start()
posted @ 2021-04-26 17:34  黑影Poco  阅读(110)  评论(0)    收藏  举报