python中的queue模块其实是对数据结构中栈和队列这种数据结构的封装,把抽象的数据结构封装成类的属性和方法。这里主要谈下,这些方法。
数据结构基础
栈(stack)也可以说是种先行后出队列(First in Last out),这种数据结构,是先进后出的特点。
打个比方:比如我们把一本一本的书放进一个刚好能容下的桶里面,后放入的书会压着先放入的书。如果我们想要从桶里面取出书籍,那么就只有从后放入的书种先取出来。类似于这种先进后出的模型便是栈了。
队列(queue)特点是先进先出(First in First out)。
打个比方:我们去食堂排队的时候,总是先去排队的人能够先打到饭,后进入队列排队的人总是后打到饭。这样的数据类型便成为队列。
如果还想学习更多关于数据结构的知识,可以去买本书籍,推荐《大话数据结构》,这本书很浅显易懂的讲解了数据结构的知识。这本书一个大佬也推出了一个配套的教学视频,《小甲鱼数据结构》(上bilibili.com就可以搜索到)。
queue模块中表达队列
在队列中涉及到这样的几个操作:入队
(把数据添加到队尾)、出队
(从队首取出一个数据)、队列初始化
(创建一个队列)、销毁一个队列
(把整个队列的数据从内存中删除)、判断队列是否为空
、判断队列是否满
、获取队列的长度
。
python封装好的队列方法
import queue
q = queue.Queue(3) # 调用构造函数,初始化一个大小为3的队列
print(q.empty()) # 判断队列是否为空,也就是队列中是否有数据
# 入队,在队列尾增加数据, block参数,可以是True和False 意思是如果队列已经满了则阻塞在这里,
# timeout 参数 是指超时时间,如果被阻塞了那最多阻塞的时间,如果时间超过了则报错。
q.put(13, block=True, timeout=5)
print(q.full()) # 判断队列是否满了,这里我们队列初始化的大小为3
print(q.qsize()) # 获取队列当前数据的个数
# block参数的功能是 如果这个队列为空则阻塞,
# timeout和上面一样,如果阻塞超过了这个时间就报错,如果想一只等待这就传递None
print(q.get(block=True, timeout=None))
# queue模块还提供了两个二次封装了的函数,
q.put_nowait(23) # 相当于q.put(23, block=False)
q.get_nowait() # 相当于q.get(block=False)
此外,queue模块实现了面向多生产线程、多消费线程的队列。
task_done()
意味着之前入队的一个任务已经完成。由队列的消费者线程调用。每一个get()调用得到一个任务,接下来的task_done()调用告诉队列该任务已经处理完毕。
如果当前一个join()正在阻塞,它将在队列中的所有任务都处理完时恢复执行(即每一个由put()调用入队的任务都有一个对应的task_done()调用)。
join()
阻塞调用线程,直到队列中的所有任务被处理掉。
只要有数据被加入队列,未完成的任务数就会增加。当消费者线程调用task_done()(意味着有消费者取得任务并完成任务),未完成的任务数就会减少。当未完成的任务数降到0,join()解除阻塞。
这两个方法到底怎么用呢?下面我给出两个例子:
import queue
q = queue.Queue(3)
q.put(13, block=True, timeout=5)
q.put_nowait(23)
q.task_done()
print(q.get())
q.join()
这段代码执行完后会一直阻塞着
import queue
q = queue.Queue(3)
q.put(13, block=True, timeout=5)
q.task_done()
q.put_nowait(23)
q.task_done()
print(q.get())
q.join()
这段代码执行后并不会会阻塞着,这是为什么呢?
其实为了实现多线程环境下对队列的支持,当我们调用put的时候可以看做我们给这个队列增加了一个任务,只有到调用task_done()
函数是才表示完成了一个任务。而join()
函数表示我们所有的任务都完成后才会不被阻塞。
python封装好的栈方法
栈的方法和队列的一模一样,只是有一点不同,我们在调用,put()
和get()
的顺序是不一样的。其他的东西都是和上面队列是一样的。
python封装好的优先队列方法
什么是优先队列:
普通的队列其实是:先进后出,或者是先进先出。
但是优先队列就不一样了,它是怎么出的规则不和进入的顺序有关,是和他的优先级有关,当入队的时候我们就会根据这个数据的优先级进行排序,优先级高的就排在前面,然后出队的时候就是先出队。
看这样一个例子:
import queue
q = queue.PriorityQueue(4)
q.put((1,'abcb'))
q.put((1,'abc1'))
q.put((1,'abc3'))
q.put((2,'abc4'))
print(q.get())
print(q.get())
print(q.get())
print(q.get())
这里会根据数据的大小比较进行排序,然后在调用get()
时根据优先顺序进行出队列。
python封装好的双向队列方法
可以把双向队列看做是队列和栈的一个升级版。
栈是在一端进行入栈和出站,而队列是在一端入栈一端出栈。
而双向队列则是两端都可以进同时也可以出。
import queue
q = queue.deque(3) # 初始化一个双向队列
q.append(12) # 右边进
q.pop() # 右边出
q.appendleft(34) # 左边进
q.popleft() # 左边出
python自己有提供的内存回收机制,所以不需要我们手动销毁队列或者栈
推荐一些好文章
简析Python中的四种队列
每周一个 Python 模块 | Queue
Python Queue 源码解读
Python 多线程|Queue队列|生产者消费者模式|