摘要:本文系统讲解 Python 标准库 queue 模块中的三种队列:先进先出队列 Queue()、后进先出队列 LifoQueue() 以及优先队列 PriorityQueue()。文章从队列的创建与基本用法入手,重点剖析 put() 和 get() 方法在满队列、空队列场景下的阻塞行为,并介绍 empty()、full() 等状态判断方法,最后通过魔术方法演示如何构造可比较对象以支持优先队列的排序需求。
目录
一、先进先出FIFO队列——Queue()
1.1、put()方法
用法
满队列使put()陷入等待
1.2、get()方法
用法
空队列使get()陷入等待
1.3、empty()方法
1.4、full()方法
1.5、get()和put()方法阻塞的释放
二、后进先出LIFO队列——LifoQueue()
三、优先队列Priority——PriorityQueue()
压入队列的元素之间必须可比较
通过魔术方法创建可比较对象
一、先进先出FIFO队列——Queue()
可设为无穷队列或有穷队列。
"""库原型""" class Queue: '''Create a queue object with a given maximum size. If maxsize is <= 0, the queue size is infinite. ''' def __init__(self, maxsize=0): self.maxsize = maxsize ...... """导入方式""" from Queue import queue1.1、put()方法
用法
"""方法原型""" ef put(self, item, block=True, timeout=None):按顺序依次将对象压入队列实例。
q = Queue() q.put(1) q.put(2) q.put(3)满队列使put()陷入等待
该情况仅针对有限长度队列,即q = queue(maxsize)
无穷等待
设置队列长度为3,第四次put()元素时,当前线程将被阻塞(IO阻塞),直到队列中有空间。
"""设置队列长度为3""" q = Queue(3) q.put(1) q.put(2) q.put(3) """试图加入第四个元素""" q.put(4)有穷等待
"""设置队列长度为3""" q = Queue(3) q.put(1) q.put(2) q.put(3) """试图加入第四个元素,线程被阻塞六秒,之后抛出异常Full""" q.put(4, timeout=6)不等待
"""设置队列长度为3""" q = Queue(3) q.put(1) q.put(2) q.put(3) """试图加入第四个元素,不会阻塞线程,直接抛出异常Full""" q.put(4, block=False)1.2、get()方法
用法
"""方法原型""" def get(self, block=True, timeout=None):从队列中取出对象,返回取出的对象本身。遵循FIFO原则,取出的值依次为1,2,此时队列中仅剩3。
q = Queue() q.put(1) q.put(2) q.put(3) print(q.get()) print(q.get())空队列使get()陷入等待
无穷等待
队列中元素数量有限,get()次数超过队列长度时,默认get()方法所处线程将被阻塞(IO阻塞),直到队列中有元素。
q = Queue() q.put(1) q.put(2) print(q.get()) print(q.get()) """第三次get()""" print(q.get())像队列中put两个元素后,当前线程执行到队列对象的第三次get()方法时,将发生阻塞。
限时等待
q = Queue() q.put(1) q.put(2) print(q.get()) print(q.get()) """第三次get(),并限制等待时长为6s""" print(q.get(timeout=6))第三次get()方法将阻塞所在线程长达6秒,6秒后抛出empty异常。
不等待
q = Queue() q.put(1) q.put(2) print(q.get()) print(q.get()) """第三次get(),由于两次get()已经将队列取空,此时直接抛异常empty""" print(q.get(block=False))1.3、empty()方法
判断队列是否为空,返回是否为空队列的判断结果。
q = Queue() """第一次判断,队列对象创建时,为空,返回True""" print(q.empty()) q.put(1) q.put(2) q.put(3) print(q.get()) print(q.get()) """第二次判断,队列对象被get()两次,此时队列中仅剩3,不为空,返回Flase""" print(q.empty()) print(q.get()) """第三次判断,队列对象被第三次get()后,队列为空,返回True""" print(q.empty())1.4、full()方法
判断有穷队列是否已满,返回队列是否已满的判断结果。
q = Queue(5) q.put(1) q.put(2) q.put(3) """第一次判断,队列中有3个元素,未满,返回False""" print(q.full()) q.put(4) q.put(5) """第二次判断,队列中新增2个元素,已满,返回True""" print(q.full())1.5、get()和put()方法阻塞的释放
q = Queue() def putdata(): time.sleep(3) q.put("test") t = threading.Thread(target=putdata, daemon=True) t.start() """子线程启动后,3秒后向队列中加入元素'test'""" """情况一:线程阻塞(IO阻塞),此时等待IO事件发生(队列中有元素),3秒后事件发生,取出元素'test'""" q.get() """情况二:线程阻塞6秒,6秒内事件发生(队列中有元素),取出元素"test",超时抛异常empty""" q.get(timeout=6) """情况三:当前不阻塞,直接抛异常Empty""" q.get(False)同理,对于put(True)方法,队列为空无法去除则阻塞,限定时间内队列依旧为空,则抛异常。
二、后进先出LIFO队列——LifoQueue()
除了元素压入和取出顺序与FIFO队列相反,其他方法与Queue()一致。
"""库原型""" class LifoQueue(Queue): '''Variant of Queue that retrieves most recently added entries first.''' ...... """导入方式""" from Queue import LifoQueue三、优先队列Priority——PriorityQueue()
优先队列的方法与Queue一致,其遵循的是按照优先级排序绝对谁先出,因此,优先队列要求元素之间必须是可比较的。
"""库原型""" class PriorityQueue(Queue): '''Variant of Queue that retrieves open entries in priority order (lowest first). Entries are typically tuples of the form: (priority number, data). ''' ...... """导入方式""" from Queue import PriorityQueue压入队列的元素之间必须可比较
q = PriorityQueue() q.put(2) q.put(3) q.put(1) print(q.get()) print(q.get()) print(q.get()) """此时队列中元素优先级排序为:1 2 3"""q = PriorityQueue() q.put(2) q.put(3) q.put(1) print(q.get()) print(q.get()) q.put(1) print(q.get()) print(q.get()) """每次压入元素,优先队列都会对队列中的元素重新排序"""q = PriorityQueue() q.put(2) q.put(3) q.put(1) print(q.get()) print(q.get()) q.put("b") q.put("a") print(q.get()) print(q.get()) """任何时刻,队列中的元素之间必须可比较,否则抛TypeError异常: '<' not supported between instances of 'str' and 'int' """通过魔术方法创建可比较对象
| 方法原型 | 含义 |
| def __eq__(self, other): | == |
| def __lt__(self, other): | < |
| def __le__(self, other): | <= |
只需要以上三个方法,>和>=比较运算将自动生成。
定义可比较类
class Student: def __init__(self, name, gender="M"): self.name = name self.gender = gender def __eq__(self, other): return self.name == other.name and self.gender == other.gender def __lt__(self, other): s1 = f"{self.gender}:{self.name}" s2 = f"{other.gender}:{other.name}" return s1 < s2 def __le__(self, other): return self < other or self == other def __repr__(self): # “调试表示”,定义 repr(obj) 和交互式环境中直接输入对象时的输出 return "<{} {}>".format(self.name, self.gender)可比较对象
q = PriorityQueue() q.put(Student('Alice', 'F')) q.put(Student('Blice', 'F')) q1 = q.get() q2 = q.get() print(q1, q2, q1 > q2)<Alice F> <Blice F> False优先队列的元素排序将按照__lt__方法进行
q = PriorityQueue() for name in ('tom', 'jerry', 'sam', 'ben', 'john'): q.put(Student(name)) q.put(Student('Alice', 'F')) for i in range(6): print(q.get())<Alice F> <ben M> <jerry M> <john M> <sam M> <tom M>