关于 Queue 你需要知道的!_优先级


Part1前言

平时我们在搬砖的过程中,难免会遇到如下问题:搬砖的人将砖送到垒砖人的手中后,再搬一块砖,如果垒砖的人还没垒完,那搬砖的人就需要等待垒砖的人垒完后才能递砖再进行下一次的搬砖。

为了解决这个问题,我们找到了一个推车,每次搬砖人都将搬来的砖放到推车中,然后垒砖的人就去推车中取,这样就避免了中间等待的时间,提高了搬砖的效率。

实际上这个例子中的推车就起到了消息队列的作用,今天我们就一起走进 ​​Queue​​ 的世界。

关于 Queue 你需要知道的!_跳出循环_02

Part2关于 Queue

​Queue​​​ 是 ​​Python​​​ 内置的,线程安全的队列库。其默认支持队列同步,实现了先入先出、后入先出和优先级队列。​​Queue​​ 在多线程通信中使用甚广。

Part3队列实践

1先进先出(FIFO)

from queue import Queue
from threading import Thread

def BanZhuan(q):
print('我开始搬砖了!')
for i in range(5):
print(f'搬砖信息:砖-{i} --> 小推车')

# 将砖放到队列中
q.put(f'砖-{i}')

def LeiZhuan(q):
print('我开始垒砖了!')
while True:

# 从队列中取砖
zhuan = q.get()

# 如果队列空了(砖搬完了),就跳出循环
if q.empty():
break
print(f'垒砖信息:{zhuan} --> 墙')



if __name__ == '__main__':

# 创建队列
q=Queue(10)

# 起一个线程进行搬砖
t1 = Thread(target=BanZhuan,args=(q,)) # 注意:args中的逗号一定要有

# 起一个线程进行垒砖
t2 = Thread(target=LeiZhuan,args=(q,))

# 开始搬砖&垒砖
t1.start()
t2.start()

关于 Queue 你需要知道的!_优先级_03代码运行结果

可以看到,砖的入列顺序为 ​​0-4​​​,砖的出列顺序也为 ​​0-4​​,即先进先出。

2后进先出(LIFO)

from queue import Queue,LifoQueue
from threading import Thread
import time,random

def BanZhuan(q):
print('我开始搬砖了!')
for i in range(5):
print(f'搬砖信息:砖-{i} --> 小推车')

# 将砖放到队列中
q.put(f'砖-{i}')


def LeiZhuan(q):
print('我开始垒砖了!')
while True:

# 从队列中取砖
zhuan = q.get()
time.sleep(random.random())
# 如果队列空了(砖搬完了),就跳出循环
if q.empty():
break
print(f'垒砖信息:{zhuan} --> 墙')



if __name__ == '__main__':

# 创建队列
q=LifoQueue(10)

# 起一个线程进行搬砖
t1 = Thread(target=BanZhuan,args=(q,)) # 注意:args中的逗号一定要有

# 起一个线程进行垒砖
t2 = Thread(target=LeiZhuan,args=(q,))

# 开始搬砖&垒砖
t1.start()
t2.start()

关于 Queue 你需要知道的!_优先级队列_04代码运行结果

如上,你会发现后进先出的队列的垒砖顺序是乱的,这是因为对于队列中的砖,我看见最新的砖我就去垒。

问题:砖没垒完就结束

这是因为我们在代码中判断,当队列为空的时候就退出。当垒砖比搬砖快的时候就会出现这个问题。我们只需要在垒砖的代码中增加短暂的等待即可。

3优先级队列(PriorityQueue)

在put的时候,传入一个元组,第一个元素为优先级,数字越小优先级越高。

from queue import Queue,LifoQueue,PriorityQueue
from threading import Thread
import time,random

def BanZhuan(q):
print('我开始搬砖了!')
for i in range(5):
print(f'搬砖信息:砖-{i} --> 小推车')

# 将砖放到队列中,优先级队列传入一个元组,第一个元素为优先级,越小优先级越高
q.put((100-i,f'砖-{i}'))


def LeiZhuan(q):
print('我开始垒砖了!')
while True:

# 从队列中取砖
zhuan = q.get()
time.sleep(random.random())
print(f'垒砖信息:{zhuan} --> 墙')

# 如果队列空了(砖搬完了),就跳出循环
if q.empty():
break




if __name__ == '__main__':

# 创建队列
q=PriorityQueue(10)

# 起一个线程进行搬砖
t1 = Thread(target=BanZhuan,args=(q,)) # 注意:args中的逗号一定要有

# 起一个线程进行垒砖
t2 = Thread(target=LeiZhuan,args=(q,))

# 开始搬砖&垒砖
t1.start()
t2.start()

关于 Queue 你需要知道的!_优先级队列_05代码运行结果

如上图,为什么 ​​100​​​ 优先级的砖会被先垒呢?因为两个线程同时开始,在等待之前,第一次 ​​get​​​ 就拿到了 ​​100​​ 优先级的砖,所以它被第一个垒。解决这个问题,我们只需要在垒砖前等待很短的时间即可(即等待搬砖完成)。

...
def LeiZhuan(q):
print('我开始垒砖了!')
while True:
time.sleep(0.1)
# 从队列中取砖
zhuan = q.get()
time.sleep(0.1)
print(f'垒砖信息:{zhuan} --> 墙')

# 如果队列空了(砖搬完了),就跳出循环
if q.empty():
break
...

关于 Queue 你需要知道的!_优先级队列_06代码运行结果

以上就是今天的全部内容了,感谢您的阅读,我们下节再会。