Python-Queue 入門


  • Queue 簡介

  • Queue 叫隊列,是數據結構中的一種,基本上所有成熟的編程語言都內置了對 Queue 的支持。
  • Python 中的 Queue 模塊實現了多生產者和多消費者模型,當需要在多線程編程中非常實用。而且該模塊中的 Queue 類實現了鎖原語,不需要再考慮多線程安全問題
  • 該模塊內置了三種類型的 Queue,分別是 class queue.Queue(maxsize=0)class queue.LifoQueue(maxsize=0) 和 class queue.PriorityQueue(maxsize=0)。它們三個的區別僅僅是取出時的順序不一致而已。
  • Queue 是一個 FIFO 隊列,任務按照添加的順序被取出。

    LifoQueue 是一個 LIFO 隊列,類似堆棧,后添加的任務先被取出。

    PriorityQueue 是一個優先級隊列,隊列里面的任務按照優先級排序,優先級高的先被取出。

  • Queue 常用操作

  • 類和異常

  • 1 class queue.Queue(maxsize=0)
    2 class queue.LifoQueue(maxsize=0)
    3 class queue.PriorityQueue(maxsize=0)

     

  • 如你所見,就是上面所說的三種不同類型的內置隊列,其中 maxsize 是個整數,用於設置可以放入隊列中的任務數的上限。當達到這個大小的時候,插入操作將阻塞至隊列中的任務被消費掉。如果 maxsize 小於等於零,則隊列尺寸為無限大。
  • 1 exception queue.Empty
    2 # 對空的 Queue 對象調用非阻塞的 get() (or get_nowait()) 時,會引發該異常。
    3 
    4 exception queue.Full
    5 # 對滿的 Queue 對象調用非阻塞的 put() (or put_nowait()) 時,會引發該異常。

     

  • 常用操作

  • 添加任務

  • 向隊列中添加任務,直接調用 put() 函數即可
  • 1 import queue
    2 >>> q = queue.Queue(maxsize=1)
    3 >>> q.put(100)

     

  • put() 函數完整的函數簽名如下 Queue.put(item, block=True, timeout=None),如你所見,該函數有兩個可選參數。
  • 默認情況下,在隊列滿時,該函數會一直阻塞,直到隊列中有空余的位置可以添加任務為止。如果 timeout 是正數,則最多阻塞 timeout 秒,如果這段時間內還沒有空余的位置出來,則會引發 Full 異常。
  •  1 >>> import queue
     2 >>> q = queue.Queue(maxsize=1)
     3 >>> q.put(100)
     4 >>> q.put(100,True,2)
     5 Traceback (most recent call last):
     6   File "<stdin>", line 1, in <module>
     7   File "E:\Python37-32\lib\queue.py", line 147, in put
     8     raise Full
     9 queue.Full # 創建一個容量為 1 的隊列,2 秒內沒有位置添加任務則引發 Full 異常
    10 >>> q.put(100) # 該方法會一直阻塞

     

  • 當 block 為 false 時,timeout 參數將失效。同時如果隊列中沒有空余的位置可添加任務則會引發 Full 異常,否則會直接把任務放入隊列並返回,不會阻塞。
  •  1 >>> import queue
     2 >>> q = queue.Queue(maxsize=1)
     3 >>> q.put(100)
     4 >>> q.put(100,False,2)
     5 Traceback (most recent call last):
     6   File "<stdin>", line 1, in <module>
     7   File "E:\Python37-32\lib\queue.py", line 136, in put
     8     raise Full
     9 queue.Full
    10 # 創建一個容量為 1 的隊列,在第二次放入任務時指定為非阻塞模式,則會立刻引發 Full 異常

     

  • 另外,還可以通過 Queue.put_nowait(item) 來添加任務,相當於 Queue.put(item, False),不再贅述。同樣,在隊列滿時,該操作會引發 Full 異常。
  • 獲取任務

  • 從隊列中獲取任務,直接調用 get() 函數即可
  • 1 >>> import queue
    2 >>> q = queue.Queue()
    3 >>> q.put(100)
    4 >>> q.get()
    5 100

     

  •  put() 函數一樣,get() 函數也有兩個可選參數,完整簽名如下 Queue.get(block=True, timeout=None)
  • 默認情況下,當隊列空時調用該函數會一直阻塞,直到隊列中有任務可獲取為止。如果 timeout 是正數,則最多阻塞 timeout 秒,如果這段時間內還沒有任務可獲取,則會引發Empty 異常。
  •  1 >>> import queue
     2 >>> q = queue.Queue()
     3 >>> q.put(100)
     4 >>> q.get()
     5 100
     6 >>> q.get(True,2)
     7 Traceback (most recent call last):
     8   File "<stdin>", line 1, in <module>
     9   File "E:\Python37-32\lib\queue.py", line 178, in get
    10     raise Empty
    11 _queue.Empty # 2 秒鍾內沒有任務可獲取則引發 Empty 異常
    12 >>> q.get() # 該方法會一直阻塞

     

  • 當 block 為 false 時,timeout 參數將失效。同時如果隊列中沒有任務可獲取則會立刻引發 Empty 異常,否則會直接獲取一個任務並返回,不會阻塞。
  •  1 >>> import queue
     2 >>> q = queue.Queue()
     3 >>> q.put(100)
     4 >>> q.get()
     5 100
     6 >>> q.get(False,2)
     7 Traceback (most recent call last):
     8   File "<stdin>", line 1, in <module>
     9   File "E:\Python37-32\lib\queue.py", line 167, in get
    10     raise Empty
    11 _queue.Empty 
    12 # 指定為非阻塞模式,隊列為空則立即引發 Empty 異常

     

  • 另外,還可以通過 Queue.get_nowait() 來獲取任務,相當於 Queue.get(False),不再贅述。同樣,在隊列為空時,該操作會引發 Empty 異常。
  • 其他常用方法

  • 獲取隊列大小

  • 1 >>> import queue
    2 >>> q = queue.Queue()
    3 >>> q.put(100)
    4 >>> q.put(200)
    5 >>> q.qsize()
    6 2

     

  • 判斷隊列是否空

  • 如果隊列為空,返回 True ,否則返回 False 。如果 empty() 返回 True ,不保證后續調用的 put() 不被阻塞。類似的,如果 empty() 返回 False ,也不保證后續調用的 get() 不被阻塞。
  • 判斷隊列是否滿

  • 如果隊列是滿的返回 True ,否則返回 False 。如果 full() 返回 True 不保證后續調用的 get() 不被阻塞。類似的,如果 full() 返回 False 也不保證后續調用的 put() 不被阻塞。
  •  1 >>> import queue
     2 >>> q = queue.Queue(maxsize=1)
     3 >>> q.empty()
     4 True
     5 >>> q.full()
     6 False
     7 >>> q.put(100)
     8 >>> q.empty()
     9 False
    10 >>> q.full()
    11 True

     

  • 隊列對比

  • FIFO 隊列

  • queue.Queue() 是 FIFO 隊列,出隊順序跟入隊順序是一致的。
  • 1 import queue
    2 q = queue.Queue()
    3 for index in range(10):
    4     q.put(index)
    5 while not q.empty():
    6     print(q.get(), end=", ")
    7 ## 輸出結果如下
    8 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

     

  • LIFO 隊列

  • queue.LifoQueue() 是 LIFO 隊列,出隊順序跟入隊順序是完全相反的,類似於棧。
  • import queue
    q = queue.LifoQueue() # 創建一個 LIFO 隊列
    for index in range(10):
        q.put(index)
    while not q.empty():
        print(q.get(), end=", ")
    ## 輸出結果如下
    9, 8, 7, 6, 5, 4, 3, 2, 1, 0,

     

  • 優先級隊列

    優先級隊列中的任務順序跟放入時的順序是無關的,而是按照任務的大小來排序,最小值先被取出。那任務比較大小的規則是怎么樣的呢。

  • 如果是內置類型,比如數值或者字符串,則按照自然順序來比較排序。

  • import queue
    q = queue.PriorityQueue()
    for index in range(10,0,-1):
        q.put(index)
    while not q.empty():
        print(q.get(), end=", ")
    ## 輸出結果如下
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10,

     

  • 如果是列表或者元祖,則先比較第一個元素,然后比較第二個,以此類推,直到比較出結果

  • import queue
    q = queue.PriorityQueue()
    q.put(["d","b"])
    q.put(["c","b"])
    while not q.empty():
        print(q.get(), end=", ")
    ## 輸出結果如下
    ['c', 'b'], ['d', 'b'],

     

  • 注意,因為列表的比較對規則是按照下標順序來比較的,所以在沒有比較出大小之前 ,隊列中所有列表對應下標位置的元素類型要一致。
  • 好比 [2,1] 和 ["1","b"] 因為第一個位置的元素類型不一樣,所以是沒有辦法比較大小的,所以也就放入不了優先級隊列。
  • 然而對於 [2,1] 和 [1,"b"] 來說即使第二個元素的類型不一致也是可以放入優先級隊列的,因為只需要比較第一個位置元素的大小就可以比較出結果了,就不需要比較第二個位置元素的大小了。
  • 但是對於 [2,1] 和 1[2,"b"] 來說,則同樣不可以放入優先級隊列,因為需要比較第二個位置的元素才可以比較出結果,然而第二個位置的元素類型是不一致的,無法比較大小。
  • 綜上,也就是說,直到在比較出結果之前,對應下標位置的元素類型都是需要一致的
  • 如果是自定義類型,需要實現 __lt__ 比較函數

  • 下面我們自定義一個動物類型,希望按照年齡大小來做優先級排序。年齡越小優先級越高。
  • import queue
    q = queue.PriorityQueue()
    
    class Animal:
        def __init__(self, age, name):
            self.age = age
            self.name = name
        def __lt__(self, other): # 實現 < 操作
            return self.age < other.age # 如果將 < 變成 > 則相當於逆序
    
    q.put(Animal(3,"cat"))
    q.put(Animal(2,"dog"))
    
    while not q.empty():
        animal = q.get()
        print(animal.name, animal.age, end=", ")
    ## 輸出結果如下
    dog 2, cat 3,

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM