day9-队列queue和生产者消费者模型

一、概述

   queue is especially useful in threaded programming when information must be exchanged safely between multiple threads.(在多个线程之间安全的交换数据信息,队列在多线程编程中特别有用。)

  队列的类型:

  1. class queue.Queue(maxsize=0)  #先进先出,后进后出
  2. class queue.LifoQueue(maxsize=0)  # last in fisrt out,后进先出
  3. class queue.PriorityQueue(maxsize=0) # 存储数据式,可设置优先级别的队列

  Constructor for a priority queue. maxsize is an integer that sets the upperbound limit on the number of items that can be placed in the queue. Insertion will block once this size has been reached, until queue items are consumed. If maxsize is less than or equal to zero, the queue size is infinite.

  The lowest valued entries are retrieved first (the lowest valued entry is the one returned by sorted(list(entries))[0]). A typical pattern for entries is a tuple in the form: (priority_number, data).

  为什么需要队列呐?

  1. 提高双方的效率,你只需要把数据放到队列中,中间去干别的事情。
  2. 完成了程序的解耦性,两者关系依赖性没有不大。

二、队列类别

2.1、class queue.Queue(maxsize=0)

说明:先进先出,后进后出

>>> import queue
>>> q = queue.Queue()   #普通队列
>>> q.put(1)  #先放进1,2
>>> q.put(2)
>>> q.get()
1
>>> q.get()   #先取到的是1,2
2

2.2、class queue.LifoQueue(maxsize=0)

说明:是先进后出,后进新出规则,last in fisrt out

>>> import queue
>>> q = queue.LifoQueue() #定义一个普通队列
>>> q.put(1)   #先放进去1,2
>>> q.put(2)
>>> q.get()
2
>>> q.get()  #取出来是2,1
1

2.3、class queue.PriorityQueue(maxsize=0)

说明:根据优先级来取数据。存放数据的格式  : Queue.put((priority_number,data)),priority_number越小,优先级越高。

>>> import queue
>>> q = queue.PriorityQueue()
>>> q.put((1,"d1"))
>>> q.put((-1,"d2"))
>>> q.put((6,"d3"))
>>> q.get()
(-1, 'd2')
>>> q.get()
(1, 'd1')
>>> q.get()
(6, 'd3')

三、队列方法

3.1、exception queue.Empty

英文说明:Exception raised when non-blocking get() (or get_nowait()) is called on a Queue object which is empty.

中文解释:当队列中的数据为空时,就会抛出这个异常。

>>> import queue
>>> q = queue.Queue()
>>> q.get(block=False)   #获取不到的时候
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\Python\Python35\lib\queue.py", line 161, in get
    raise Empty
queue.Empty

3.2、 exception queue.Full

英文:Exception raised when non-blocking put() (or put_nowait()) is called on a Queue object which is full.

中文:当队列中满了以后,再放数据的话,就会抛出此异常。

>>> import queue
>>> q = queue.Queue(maxsize=1)  #创建队列实例,并且设置最大值为1
>>> q.put(1)
>>> q.put(1,block=False)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\Python\Python35\lib\queue.py", line 130, in put
    raise Full
queue.Full

3.3、Queue.qsize()

说明:查看队列的大小

>>> import queue
>>> q = queue.Queue()
>>> q.put(1)
>>> q.qsize()   #查看队列的大小
1

3.4、Queue.empty()

说明:队列如果为空返回True,不为空返回False

>>> import queue
>>> q = queue.Queue()
>>> q.put(1)
>>> q.empty()  #队列不为空
False
>>> q.get()
1
>>> q.empty() #队列为空
True

3.5、Queue.full()

说明:队列如果满了,返回True,没有满返回False

>>> import queue
>>> q = queue.Queue(maxsize=1)  #设置队列的大小为1
>>> q.full()   #队列没有满
False
>>> q.put(1)
>>> q.full()   #队列已满
True

3.6、Queue.put(item,block=True,timeout=None)

英文解释:Put item into the queue. If optional args block is true and timeout is None (the default), block if necessary until a free slot is available. If timeout is a positive number, it blocks at most timeout seconds and raises the Full exception if no free slot was available within that time. Otherwise (block is false), put an item on the queue if a free slot is immediately available, else raise the Full exception (timeout is ignored in that case).

中文解释:把数据插入队列中。block参数默认为true,timeout默认值是None。如果blcok为false的话,那么在put时候超过设定的maxsize的值,就会报full 异常。如果timeout设置值得话,说明put值得个数超过maxsize值,那么会在timeout几秒之后抛出full异常。

>>> import queue
>>> q = queue.Queue(maxsize=1)  #是定队列的大小为1
>>> q.put(1)
>>> q.put(1,block=False)   #block不会阻塞,会full异常
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\Python\Python35\lib\queue.py", line 130, in put
    raise Full
queue.Full
>>> q.put(1,timeout=1)    #超过1秒,则会报full异常
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\Python\Python35\lib\queue.py", line 141, in put
    raise Full
queue.Full

3.7、Queue.put_nowait(item)

说明:这个其实等同于Queue.put(item,block=False)或者是Queue.put(item,False)

>>> import queue
>>> q = queue.Queue(maxsize=1)
>>> q.put(1)
>>> q.put_nowait(1)   #等同于q.put(1,block=False)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\Python\Python35\lib\queue.py", line 184, in put_nowait
    return self.put(item, block=False)
  File "D:\Python\Python35\lib\queue.py", line 130, in put
    raise Full
queue.Full

3.8、Queue.get(block=True,timeout=None)

英文解释:Remove and return an item from the queue. If optional args block is true and timeout is None (the default), block if necessary until an item is available. If timeout is a positive number, it blocks at most timeout seconds and raises the Empty exception if no item was available within that time. Otherwise (block is false), return an item if one is immediately available, else raise the Empty exception (timeout is ignored in that case).

中文解释:移除并返回队列中的序列。参数block=true并且timeout=None。如果block=false的话,那么队列为空的情况下,就直接Empty异常。如果timeout有实际的值,这个时候队列为空,执行get的时候,则时隔多长时间则报出Empty的异常。

>>> import queue
>>> q = queue.Queue()
>>> q.put(1)
>>> q.get()
1
>>> q.get(block=False)    #获取不到值,直接抛Empty异常
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\Python\Python35\lib\queue.py", line 161, in get
    raise Empty
queue.Empty
>>> q.get(timeout=1)    #设置超时时间,抛出Empty异常
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\Python\Python35\lib\queue.py", line 172, in get
    raise Empty
queue.Empty

3.9、Queue.get_nowait(item)

说明:其实这个等同于Queue.get(block=False)或者Queue.get(False)

>>> import queue
>>> q = queue.Queue()
>>> q.put(1)
>>> q.get()
1
>>> q.get_nowait()   #等同于q.get(block=False)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\Python\Python35\lib\queue.py", line 192, in get_nowait
    return self.get(block=False)
  File "D:\Python\Python35\lib\queue.py", line 161, in get
    raise Empty
queue.Empty

3.10、Queue.task_done()

英文解释:Indicate that a formerly enqueued task is complete. Used by queue consumer threads. For each get() used to fetch a task, a subsequent call to task_done() tells the queue that the processing on the task is complete.

中文解释:这个函数告诉队列消费者每消费一条信息,则要告诉消费者你已经消费了一个包子。

3.11、Queue.join()

说明:block直到queue被消费完毕

英文:If a join() is currently blocking, it will resume when all items have been processed (meaning that a task_done() call was received for every item that had been put() into the queue).

Raises a ValueError if called more times than there were items placed in the queue.

中文解释:如果生产者生产10个包子,那么要等消费者把这个10个包子全部消费完毕,生产者才能继续往下执行。

四、生产者消费者模型

  在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

4.1、为什么要使用生产者和消费者模式

  在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

4.2、什么是生产者消费者模式

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

4.3、生成者消费者模型例子

import threading
import queue
 
def producer():
    "生产者"
    for i in range(10):
        q.put("骨头 %s" % i )
 
    print("开始等待所有的骨头被取走...")
    q.join()
    print("所有的骨头被取完了...")
 
def consumer(n):
    "消费者"
    while q.qsize() >0:
        print("%s 取到" %n  , q.get())
        q.task_done() #告知这个任务执行完了

q = queue.Queue()

p = threading.Thread(target=producer,)
p.start()
 
c1 = consumer("shabihong")

4.4、边生产边消费的例子

import time,random
import queue,threading
q = queue.Queue()
def Producer(name):
  count = 0
  while count <20:
    time.sleep(random.randrange(3))
    q.put(count)
    print('Producer %s has produced %s baozi..' %(name, count))
    count +=1
def Consumer(name):
  count = 0
  while count <20:
    time.sleep(random.randrange(4))
    if not q.empty():
        data = q.get()
        print(data)
        print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
    else:
        print("-----no baozi anymore----")
    count +=1
p1 = threading.Thread(target=Producer, args=('A',))
c1 = threading.Thread(target=Consumer, args=('B',))
p1.start()
c1.start()

五、逻辑图

图解:

  1. 生产者生产,消费者消费。
  2. 消费者每消费一次,都要去执行以下task_done()方法,来告诉消费者你已经消费成功,相当于吃完饭,你应该给钱了。
  3. 消费者每消费一次,则队列中计数器会做减1操作。
  4. 当队列中的计数器为0的时候,则生产者不阻塞,继续执行,不为0的时候,则阻塞,直到消费者消费完毕为止。

 

转载于:https://www.cnblogs.com/zhangqigao/articles/7274834.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值