queue模块简介
queue模块提供了创建和使用队列的底层封装,而且是线程安全的,非常适合用在线程之间进行数据交互。
queue模块提供queue.Queue(FIFO队列),queue.LifoQueue(LIFO队列),以及queue.PriorityQueue(优先级队列)。从3.7版本开始,queue还提供了一个SimpleQueue队列。
四种不同类型的队列,它们之间的主要区别在于数据入队列之后出队列的顺序不同。
queue模块的官方链接
一,类型
1,queue.Queue(maxsize=0)
先进先出(First In First Out: FIFO)队列,先进入队列的数据拥有先出队列的优先权。
参数 maxsize 是一个整数,用于设置队列的最大长度。一旦队列达到上限,插入数据将会被阻塞,直到有数据出队列之后才可以继续插入。如果 maxsize 设置为小于或等于零,则队列的长度没有限制。
使用范例:
import queue
q = queue.Queue(maxsize=10) # 创建 Queue 队列
for i in range(10):
q.put(('序列%d'%i))
for i in range(10):
print(q.get())
输出结果
序列0
序列1
序列2
序列3
序列4
序列5
序列6
序列7
序列8
序列9
2,queue.LifoQueue(maxsize=0)
后进先出(Last In First Out: LIFO)队列,后进入队列的数据拥有先出队列的优先权,就像数据结构中的栈一样。
参数 maxsize 是一个整数,用于设置队列的最大长度。一旦队列达到上限,插入数据将会被阻塞,直到有数据出队列之后才可以继续插入。如果 maxsize 设置为小于或等于零,则队列的长度没有限制。
使用范例:
import queue
q = queue.LifoQueue(10)
for i in range(10):
q.put(('序列%d'%i))
for i in range(10):
print(q.get())
输出结果
序列9
序列8
序列7
序列6
序列5
序列4
序列3
序列2
序列1
序列0
3,PriorityQueue(maxsize=0)
优先级队列会比较队列中每个数据的大小,值小的数据拥有先出队列的优先权。数据一般以元组的形式((priority_number, data))插入。如果队列中的数据没有可比性,那么数据将被包装在一个类中,忽略数据值,仅比较优先级数字。
参数 maxsize 是一个整数,用于设置队列的最大长度。一旦队列达到上限,插入数据将会被阻塞,直到有数据出队列之后才可以继续插入。如果 maxsize 设置为小于或等于零,则队列的长度没有限制。
使用范例:
import queue,random
q = queue.PriorityQueue(maxsize=0) # 创建 PriorityQueue 队列
labels=['语文','数学','英语','物理','化学','生物']
for i in labels:
q.put((random.randint(0,5),i))
for i in range(6):
print(q.get())
for i in labels:
q.put(i)
for i in range(6):
print(q.get())
输出结果
(2, '数学')
(2, '物理')
(3, '化学')
(3, '语文')
(5, '生物')
(5, '英语')
化学
数学
物理
生物
英语
语文
4,queue.SimpleQueue
先进先出类型的简单队列,没有大小限制,相比于前三类队列缺少一些高级功能(task_done()和join())。
使用范例:
import queue
q = queue.SimpleQueue()
for i in range(10):
q.put('序列%d'%i)
for i in range(10):
print(q.get())
输出结果
序列0
序列1
序列2
序列3
序列4
序列5
序列6
序列7
序列8
序列9
二,异常
queue.Empty 异常:当队列为空,从队列中取数据时会引发 queue.Empty 异常。
queue.Full 异常:当队列中元素个数达到上限,继续往往队列存放数据会引发 queue.Full 异常。
三,操作
1,Queue.qsize()
返回队列中数据元素的个数。
使用范例:
import queue
q = queue.Queue()
for i in range(10):
q.put('序列%d'%i)
print(q.qsize())
输出结果
1
2
3
4
5
6
7
8
9
10
2,Queue.empty()
如果队列为空,返回 True,否则返回False。
使用范例:
import queue
q = queue.Queue(maxsize=10)
for i in range(10):
print(q.empty())
q.put('序列%d'%i)
输出结果
True
False
False
False
False
False
False
False
False
False
3,Queue.full()
如果队列中元素个数达到上限,返回 True,否则返回 False。
使用范例:
import queue
q = queue.Queue(maxsize=10)
for i in range(10):
q.put('序列%d'%i)
print(q.full())
输出结果
False
False
False
False
False
False
False
False
False
True
4,Queue.put(item, block=True, timeout=None)
item:放入队列中的数据元素。
block:当队列中元素个数达到上限继续往里放数据时,如果 block=False,直接引发 queue.Full 异常;如果 block=True,且 timeout=None,则一直等待直到有数据出队列后可以放入数据;如果 block=True,且 timeout=N,则等待 N 秒,如果队列中还没有位置放入数据就引发 queue.Full 异常。
timeout:设置超时时间。
使用范例:
import queue
try:
q = queue.Queue(10)
for i in range(20):
q.put('序列%d'%i,block=True,timeout=1)
except queue.Full:
print('queue.Full')
输出结果
queue.Full
5,Queue.put_nowait(item)
相当于 Queue.put(item, block=False),当队列中元素个数达到上限继续往里放数据时直接引发 queue.Full 异常。
使用范例:
import queue
try:
q = queue.Queue(10) # 设置队列上限为2
for i in range(20):
q.put_nowait('序列%d'%i)
except queue.Full:
print('queue.Full')
输出结果
queue.Full
6,Queue.get(block=True, timeout=None)
从队列中取出数据并返回数据内容。
block:当队列中没有数据元素继续取数据时:如果 block=False,直接引发 queue.Empty 异常;如果 block=True,且 timeout=None,则一直等待直到有数据入队列后可以取出数据;如果 block=True,且 timeout=N,则等待 N 秒,如果队列中还没有数据放入的话就引发 queue.Empty 异常。
timeout:设置超时时间。
使用范例:
import queue
try:
q = queue.Queue()
q.get(block = True, timeout = 1)
except queue.Empty:
print('queue.Empty')
输出结果
queue.Empty
7,Queue.get_nowait()
相当于 Queue.get(block=False),当队列中没有数据元素继续取数据时直接引发 queue.Empty 异常。
使用范例:
import queue
try:
q = queue.Queue()
q.get_nowait()
except queue.Empty:
print('queue.Empty')
输出结果
queue.Empty
8,Queue、LifoQueue和PriorityQueue对象的高级方法
SimpleQueue是Python3.7版本中新加入的特性,与Queue、LifoQueue和PriorityQueue三种队列相比缺少了task_done和join的高级使用方法。
task_done:每个get用于获取一个数据元素, 后续调用task_done告诉队列,该数据的处理已经完成。如果被调用的次数多于放入队列中的元素个数,将引发ValueError异常。
join:一直阻塞队列直到所有被取出数据元素都被执行。当未完成任务的计数等于0,join就不会阻塞。
使用范例:
import queue
q = queue.Queue()
q.put('语文')
q.put('数学')
q.put('英语')
for i in range(3):
print(q.get())
q.task_done() # 如果不执行 task_done,join 会一直处于阻塞状态
q.join()
输出结果
语文
数学
英语
三,典型应用
生产者和消费者线程分别生产数据和消费数据,先生产后消费。
采用task_done和join确保处理信息在多个线程间安全交换,生产者生产的数据能够全部被消费者消费掉。
import queue,threading,time
# 生产者
class Producer(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self, name='Producer')
self._data = queue
def run(self):
for i in range(5):
print("%s-%d is producing %d to the queue." % (self.name, self.ident, i))
self._data.put(i)
time.sleep(i % 5)
print("%s-%d finished." % (self.name, self.ident))
# 消费者
class Consumer(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self, name='Consumer')
self._data = queue
def run(self):
for i in range(5):
val = self._data.get()
print("%s-%d is consuming %d." % (self.name, self.ident, val))
time.sleep(0.5)
self._data.task_done()
print("%s-%d is finished." % (self.name, self.ident))
def work():
q = queue.Queue()
producer = Producer(q)
consumer = Consumer(q)
producer.start()
consumer.start()
q.join()
producer.join()
consumer.join()
print('All threads terminate!')
if __name__ == '__main__':
work()
输出结果
Producer-9660 is producing 0 to the queue.
Producer-9660 is producing 1 to the queue.
Consumer-13664 is consuming 0.
Consumer-13664 is consuming 1.
Producer-9660 is producing 2 to the queue.
Consumer-13664 is consuming 2.
Producer-9660 is producing 3 to the queue.
Consumer-13664 is consuming 3.
Producer-9660 is producing 4 to the queue.
Consumer-13664 is consuming 4.
Consumer-13664 is finished.
Producer-9660 finished.
All threads terminate!