队列Queue
Python中队列实现了线程安全,即在多线程对同一个队列进行操作时候,线程会独占资源直到这个线程释放,在线程独占资源这个过程中其他线程无法对该队列进行操作。
queue
form queue import Queue q = Queue() # 实例化一个队列,q = Queue(size=None) q.put(3) # 放入一个元素 elem = q.get() # 取出一个元素 print(q.empty(), q.qsize) # 显示是否为空 和 当前元素个数 # 当queue中的元素满了再进行put操作,或者queue中元素为空时进行get操作时,程序会一直阻塞。 elem = q.get() # 此时程序会一直阻塞。可以设置等待时间 elem = q.get(block=True, timeout=10) # 阻塞10秒,拿到数据继续执行,拿不到数据报错。
block 参数指定该次取值是阻塞的,设置为False表示不阻塞,没有数据直接报错,也可以使用q. get_nowait()
,默认调用get(block=False)
。
queue中提供了常用的方法如下
__init__(maxsize:int) _init(maxsize) empty() full() get(block, timeout) get_nowait() put(item, block, timeout) put_nowait(item) qsize() join() task_done()
PriortyQueue(优先队列)
优先队列和queue有些许的差别。它的底层使用堆数据结构来进行处理。
优先队列顾名思义可以根据消息的等级实现消息选择性的弹出,每次取出的值为所有数据中优先级最高的那个数据,也就会这个堆的堆顶元素
from queue import PriorityQueue q = PriorityQueue() q.put(10) q.put(5) q.put(9) while not q.empty(): print(q.get(), end=",") ====输出结果===== 5,9,10
默认每次将“值”最小的元素优先返回,注意:堆中的第一个元素输出后,将最后一个元素置顶,再进行堆调整(queue和LIFOqueue不需要),调整的过程中涉及两个元素之间的大小比较,所以这些数据的数据类型必须可以两两大小比较。否则将会报错。
queue的线程安全误区
上面的代码在单线程中是安全的,但是在线程中使用会出现问题,问题在于
while not q.empty: q.get() # 当只剩下最后一个元素,多个线程同时通过了not empty判断并未取值,然后在取值的时候,未必还有元素,此时线程就阻塞了。
文章一开始说的线程安全是指,在一次操作queue时,保证了只有一条线程操作。比如get,put,qsize,empty等单次操作。模块内部会使用锁的机制来保证线程安全,进入前加锁,操作结束时解锁。