前言
平时我们在搬砖的过程中,难免会遇到如下问题:搬砖的人将砖送到垒砖人的手中后,再搬一块砖,如果垒砖的人还没垒完,那搬砖的人就需要等待垒砖的人垒完后才能递砖再进行下一次的搬砖。
为了解决这个问题,我们找到了一个推车,每次搬砖人都将搬来的砖放到推车中,然后垒砖的人就去推车中取,这样就避免了中间等待的时间,提高了搬砖的效率。
实际上这个例子中的推车就起到了消息队列的作用,今天我们就一起走进 Queue
的世界。
网络异常,图片无法展示
|
关于 Queue
Queue
是 Python
内置的,线程安全的队列库。其默认支持队列同步,实现了先入先出、后入先出和优先级队列。Queue
在多线程通信中使用甚广。
队列实践
先进先出(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() 复制代码
网络异常,图片无法展示
|
可以看到,砖的入列顺序为
0-4
,砖的出列顺序也为0-4
,即先进先出。
后进先出(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() 复制代码
网络异常,图片无法展示
|
如上,你会发现后进先出的队列的垒砖顺序是乱的,这是因为对于队列中的砖,我看见最新的砖我就去垒。
问题:砖没垒完就结束
这是因为我们在代码中判断,当队列为空的时候就退出。当垒砖比搬砖快的时候就会出现这个问题。我们只需要在垒砖的代码中增加短暂的等待即可。
优先级队列(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() 复制代码
网络异常,图片无法展示
|
如上图,为什么
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 ... 复制代码
网络异常,图片无法展示
|
以上就是今天的全部内容了,感谢您的阅读,我们下节再会。