Python 标准库之 Queue
1. Queue 概念
隊列 Queue 多應用在多線程應用中,多線程訪問共享變量。對于多線程而言,訪問共享變量時,隊列 Queue 是線程安全的。
Python Queue 模塊有三種隊列及構造函數:
- Python Queue模塊的FIFO隊列先進先出。
class Queue.Queue(maxsize)
- LIFO類似于堆,即先進后出。
class Queue.LifoQueue(maxsize)
- 還有一種是優先級隊列級別越低越先出來。即隊列中的元素是一個元祖類型,(優先級級別,數據)。
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 Queuemy_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 Queueq = 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
總結
以上是生活随笔為你收集整理的Python 标准库之 Queue的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 标准库之 uuid
- 下一篇: Python 标准库之 commands