Python 标准库之 Queue

1. Queue 概念

队列 Queue 多应用在多线程应用中,多线程访问共享变量。对于多线程而言,访问共享变量时,队列 Queue 是线程安全的。

Python Queue 模块有三种队列及构造函数:

  1. Python Queue模块的FIFO队列先进先出。
   class Queue.Queue(maxsize)
  1. LIFO类似于堆,即先进后出。
   class Queue.LifoQueue(maxsize)
  1. 还有一种是优先级队列级别越低越先出来。即队列中的元素是一个元祖类型,(优先级级别,数据)。
   class Queue.PriorityQueue(maxsize)

2. Queue 常用的方法

q = Queue.Queue()
函数说明
q.qsize()返回队列的大小
q.empty()如果队列为空,返回True,反之False
q.full()如果队列满了,返回True,反之False
q.get([block[, timeout]])获取队列,timeout等待时间
q.get_nowait()相当q.get(False),无阻塞的向队列中get任务,当队列为空时,不等待,而是直接抛出empty异常,重点是理解block = False:
q.put(item)非阻塞写入队列,timeout等待时间
q.put_nowait(item)相当q.put(item, False),无阻塞的向队列中添加任务,当队列为满时,不等待,而是直接抛出full异常,重点是理解block = False
q.task_done()在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join()阻塞等待队列中任务全部处理完毕,需要配合queue.task_done使用

重点方法说明:

2.1 get() 方法

from Queue import Queue
Queue.get(self, block=True, timeout=None)

调用队列对象的 get() 方法从队头删除并返回一个项目。可选参数为 block,默认为 True。

  • 如果队列为空且 block 为 True,get() 就使调用线程暂停,直至有项目可用。
  • 如果队列为空且 block 为 False,队列将引发 Empty 异常。

2.2 put() 方法

from Queue import Queue
Queue.put(self, item, block=True, timeout=None)

调用队列对象的 put() 方法在队尾插入一个项目。put() 有三个参数,第一个 item 为必需的,为插入项目的值;第二个 block 为可选参数,默认为 True。

  • 如果队列当前为空且 block 为 True,put() 方法就使调用线程暂停,直到空出一个数据单元。
  • 如果block为 False,put 方法将引发 Full 异常

从上面说明可以看到,当一个队列为空的时候如果再用 get 取则会堵塞,所以取队列的时候一般是用到 get_nowait() 方法,这种方法在向一个空队列取值的时候会抛一个 Empty 异常,所以更常用的方法是先判断一个队列是否为空,如果不为空则取值。

from Queue import Queue

my_queue = Queue(maxsize=10)
# 定义队列时有一个默认的参数maxsize, 如果不指定队列的长度,即maxsize=0,那么队列的长度为无限长,如果定义了大于0的值,那么队列的长度就是maxsize。
a = [1, 2, 3]
my_queue.put(a)
print my_queue.get()
print my_queue.get()    # 再次调用时进程一直未结束,处于等待队列中有值的状态

3. 注意事项

3.1 阻塞模式

import Queue

q = Queue.Queue(10)

......
for i in range(10):
	q.put('A')
	time.sleep(0.5)

这是一段极其简单的代码(另有两个线程也在操作队列 q),我期望每隔 0.5 秒写一个’A’到队列中,但总是不能如愿:间隔时间有时会远远超过 0.5 秒。

原来,Queue.put()默认有 block = True 和 timeout 两个参数。当 block = True 时,写入是阻塞式的,阻塞时间由 timeout 确定。

当队列 q 被(其他线程)写满后,这段代码就会阻塞,直至其他线程取走数据。Queue.put()方法加上 block=False 的参数,即可解决这个隐蔽的问题。但要注意,非阻塞方式写队列,当队列满时会抛出 exception Queue.Full 的异常。

3.1 无法捕获 exception Queue.Empty 的异常

while True:
    ......
    try:
    	data = q.get()
    except Queue.Empty:
        break

我的本意是用队列为空时,退出循环,但实际运行起来,却陷入了死循环。这个问题和上面有点类似:Queue.get()默认的也是阻塞方式读取数据,队列为空时,不会抛出 except Queue.Empty ,而是进入阻塞直至超时。 加上block=False 的参数,问题迎刃而解。

参考:

https://blog.csdn.net/zy205817/article/details/51388479

https://blog.csdn.net/yatere/article/details/6668006

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wohu007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值