Python笔记 之 queue标准模块

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!
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值