python模块 queue--同步队列
参考文档:https://docs.python.org/zh-cn/3.8/library/queue.html
- queue模块实现了多生产者、多消费者队列。特别适用于消息必须安全地在多线程间交换的线程编程。
1、队列类型
- queue模块实现了三种类型的队列,它们的区别仅仅是条目取回的顺序。
- 在内部,这三个类型的队列使用锁来临时阻塞竞争线程;然而,它们并未被设计用于线程的重入性处理。
2、queue模块的类和异常
1、class queue.Queue(maxsize=0)
- 创建先进先出队列(FIFO)对象。
- Maxsize是一个整数,用于设置可以放置在队列中的元素数量的上限。一旦达到这个大小,插入操作将被阻塞,直到队列中的元素被消耗。
- 如果maxsize小于或等于0,则队列大小为无穷大。
- Queue类实现了所有所需的锁定语义。
2、class queue.LifoQueue(maxsize=0)
- 创建后进先出队列(LIFO)对象。
- maxsize是个整数,用于设置可以放入队列中的元素数的上限。一旦达到这个大小,插入操作将被阻塞,直到队列中的元素被消耗。
- 如果maxsize小于或等于0,则队列大小为无穷大。
3、class queue.PriorityQueue(maxsize=0)
- 创建优先级队列对象。
- Maxsize是一个整数,用于设置可以放置在队列中的元素数量的上限。一旦达到这个大小,插入操作将被阻塞,直到队列中的元素被消耗。
- 如果maxsize小于或等于0,则队列大小为无穷大。
4、class queue.SimpleQueue
- 无界的FIFO队列构造函数。简单的队列,缺少任务跟踪等高级功能。(python3.7新功能)
5、exception queue.Empty
- 对空的Queue对象,调用非阻塞的get()(或get_nowait())时,引发的异常。
6、exception queue.Full
- 对满的Queue对象,调用非阻塞的put()(或put_nowait())时,引发的异常。
3、Queue对象的方法
- 队列对象(Queue,LifoQueue,或者PriorityQueue)的公共方法。
1、Queue.put(item, block=True, timeout=None)
- 将item放入队列。
- 有两个可选参数block和timeout。
- 当block=True(默认)时,插入是阻塞式的,阻塞时间由timeout决定。
- 如果timeout=None(默认),将一直阻塞,直至有空闲插槽可用;
- 如果timeout是个正数,将最多阻塞timeout秒,如果在这段时间没有可用的空闲插槽,将引发Full异常。
- 当block=False时,插入是非阻塞式的,即当插入时队列已满将抛出Full异常。
- 当block=True(默认)时,插入是阻塞式的,阻塞时间由timeout决定。
2、Queue.get(block=True, timeout=None)
- 从队列中移除并返回一个元素。
- 有两个可选参数block和timeout。
- 当block=True(默认)时,读取是阻塞式的,阻塞时间由timeout决定。
- 如果timeout=None(默认),将一直阻塞,直至元素可得到;
- 如果timeout是个正数,将最多阻塞timeout秒,如果在这段时间内元素不能得到,将引发Empty异常。
- 当block=False时,读取是非阻塞式的,即当读取时队列为空将抛出Empty异常。
- 当block=True(默认)时,读取是阻塞式的,阻塞时间由timeout决定。
3、Queue.qsize()
- 返回队列的大致大小。因为队列大小可能被其他线程修改,所以该值为近似值。
- 注意,qsize() > 0 不保证后续的 get() 不被阻塞,qsize() < maxsize 也不保证 put() 不被阻塞。
4、Queue.empty()
- 如果队列为空,返回True,否则返回False。
- 注意,如果empty()返回True,不保证后续调用的put()不被阻塞。如果empty()返回False,也不保证后续调用的get()不被阻塞。
5、Queue.full()
- 如果队列是满的返回True,否则返回False。
- 注意,如果full()返回True不保证后续调用的get()不被阻塞。如果full()返回False也不保证后续调用的put()不被阻塞。
6、Queue.put_nowait(item)
- 相当于put(item, False)。
7、Queue.get_nowait()
- 相当于get(False)。
8、Queue.task_done()
- 表示前面排队的元素已经处理完毕。
- task_done被队列的消费者线程使用。
- 每get()一个元素,就调用task_done()告诉队列,该元素的处理已经完成。
- 如果Queue.join()当前处于阻塞状态,在所有元素都被处理后,将解除阻塞(这意味着每个已被put()放入队列的元素都会收到task_done()调用)。
- 如果被调用的次数多于放入队列中的元素数量,将引发 ValueError 异常 。
9、Queue.join()
- 阻塞至队列中所有的元素都被接收和处理完毕。
- 当元素添加到队列的时候,未完成任务的计数就会增加。每当消费者线程调用task_done()表示这个元素已经被回收,该元素所有工作已经完成,未完成计数就会减少。当未完成计数降到零的时候,join()阻塞被解除。
4、队列使用示例
1、队列的简单使用
from queue import Queue q = Queue(5)#如果不设置长度,默认为无限长 q.put('A') q.put('B') q.put('C') print('队列数据数量:', q.qsize()) print('队列是否为空:', q.empty()) print('队列是否已满:', q.full()) print('取数据:', q.get(timeout=1)) print('取数据:', q.get(timeout=1)) print('取数据:', q.get(timeout=1)) print('队列最大长度:', q.maxsize) <<< 队列数据数量: 3 队列是否为空: False 队列是否已满: False 取数据: A 取数据: B 取数据: C 队列最大长度: 5
2、task_done()和join()的使用
- 一般Queue.task_done()和Queue.join()配合使用
- task_done()的作用:消费者处理一个任务,它就通知生产者我处理了一个任务。
- 不注释q.task_done()和q.join(),我们发现produce函数在消费者消费完后才结束,而不是生产完就结束。
- 注释q.task_done()和q.join(),我们发现生产者生产完任务produce函数就结束了,而不是等到消费者消费完才结束。
- 注释q.task_done(),不注释q.join(),我们发现produce函数一直阻塞没有结束。
import time from queue import Queue from threading import Thread, Lock lock = Lock() q = Queue() def produce(): for i in range(10): lock.acquire() q.put(i) print('生产:', i) lock.release() print('生产任务完毕!') q.join() #q.join print(produce.__name__, '函数结束!') def consumer(): for i in range(10): lock.acquire() print('消费:', q.get()) q.task_done() #q.task_done if i == 4: print('休息1s...') time.sleep(1) #sleep作用:查看生产者是否阻塞 lock.release() print(consumer.__name__, '函数结束!') pro = Thread(target=produce) con = Thread(target=consumer) pro.start() con.start() con.join() print('消费者任务完成') pro.join() print('生产者任务完成')
# #