"queue" --- 同步佇列 (queue) class（類別）
******************************************

**原始碼：**Lib/queue.py

======================================================================

"queue" module（模組）實作多生產者、多消費者佇列。在執行緒程式設計中，
必須在多執行緒之間安全地交換資訊時，特別有用。此 module 中的 "Queue"
class 實作所有必需的鎖定語義 (locking semantics)。

本模块实现了三种类型的队列，它们的区别仅仅是条目的提取顺序。 在 FIFO
(first-in, first-out) 队列中，先添加的任务会先被提取。 在 LIFO (last-
in, first-out) 队列中，最近添加的条目会先被提取 (类似于一个栈)。 在优
先级队列中，条目将保持已排序状态 (使用 "heapq" 模块) 并且值最小的条目
会先被提取。

在內部，這三種型別的佇列使用鎖 (lock) 來暫時阻塞競爭執行緒；但是，它們
並不是被設計來處理執行緒內的 reentrancy（可重入）。

此外，此 module 實作一個「簡單」的 FIFO (first-in, first-out) 佇列型別
"SimpleQueue"，其特定的實作是以較少的功能為代價，來提供額外的保證。

"queue" module 定義了以下的 class 和例外：

class queue.Queue(maxsize=0)

   FIFO (first-in, first-out) 佇列的建構子 (constructor)。*maxsize* 是
   一個整數，用於設置佇列中可放置的項目數的上限。一旦達到此大小，插入
   將會阻塞，直到佇列中的項目被消耗。如果 *maxsize* 小於或等於零，則佇
   列大小為無限。

class queue.LifoQueue(maxsize=0)

   LIFO (last-in, first-out) 佇列的建構子。*maxsize* 是一個整數，用於
   設置佇列中可放置的項目數的上限。一旦達到此大小，插入將被鎖定，到佇
   列中的項目被消耗。如果 *maxsize* 小於或等於零，則佇列大小為無限。

class queue.PriorityQueue(maxsize=0)

   優先佇列的建構子。*maxsize* 是一個整數，用於設置佇列中可放置的項目
   數的上限。一旦達到此大小，插入將被阻塞，直到佇列中的項目被消耗。如
   果 *maxsize* 小於或等於零，則佇列大小為無限。

   值最小的条目会先被提取 (值最小的条目是由the lowest valued entry is
   the one that would be returned by "min(entries)" 返回的)。 条目的典
   型模式是如下形式的元组: "(priority_number, data)"。

   如果 *data* 元素為不可比較的，則可以將資料包裝在一個 class 中，該
   class 忽略資料項目並僅比較優先數：

      from dataclasses import dataclass, field
      from typing import Any

      @dataclass(order=True)
      class PrioritizedItem:
          priority: int
          item: Any=field(compare=False)

class queue.SimpleQueue

   無界的 FIFO (first-in, first-out) 佇列的建構子。簡單佇列缺少任務追
   蹤等進階功能。

   3.7 版新加入.

exception queue.Empty

   當對一個空的 "Queue" 物件呼叫非阻塞的 (non-blocking) "get()"（或
   "get_nowait()"）將引發此例外。

exception queue.Full

   當對一個已滿的 "Queue" 物件呼叫非阻塞的 "put()"（或 "put_nowait()"
   ）將引發此例外。


佇列物件
========

佇列物件（"Queue"、"LifoQueue"、"PriorityQueue"）提供下面描述的公用
method。

Queue.qsize()

   回傳佇列的近似大小。注意，qsize() > 0 並不能保證後續的 get() 不會阻
   塞，qsize() < maxsize 也不會保證 put() 不會阻塞。

Queue.empty()

   如果佇列為空，則回傳 "True"，否則回傳 "False"。如果 empty() 回傳
   "True"，則不保證後續呼叫 put() 不會阻塞。同樣，如果 empty() 回傳
   "False"，則不保證後續呼叫 get() 不會阻塞。

Queue.full()

   如果佇列已滿，則回傳 "True" ，否則回傳 "False"。如果 full() 回傳
   "True"，則不保證後續呼叫 get() 不會阻塞。同樣，如果 full() 回傳
   "False"，則不保證後續呼叫 put() 不會阻塞。

Queue.put(item, block=True, timeout=None)

   将 *item* 加入队列。 如果可选参数 *block* 为真值并且 *timeout* 为
   "None" (默认值)，则会在必要时阻塞直到有空闲槽位可用。 如为
   *timeout* 为正数，则将阻塞最多 *timeout* 秒并会在没有可用的空闲槽位
   时引发 "Full" 异常。 在其他情况下 (*block* 为假值)，则如果空闲槽位
   立即可用则将条目加入队列，否则将引发 "Full" 异常 (*timeout* 在此情
   况下将被忽略)。

Queue.put_nowait(item)

   等效於 "put(item, block=False)"。

Queue.get(block=True, timeout=None)

   從佇列中移除並回傳一個項目。如果可選的 args *block* 為 true，且
   *timeout* 為 "None"（預設值），則在必要時阻塞，直到有可用的項目。如
   果 *timeout* 是正數，則最多會阻塞 *timeout* 秒，如果該時間內沒有可
   用的項目，則會引發 "Empty" 例外。否則（*block* 為 false），如果立即
   可用，則回傳一個項目，否則引發 "Empty" 例外（在這種情況下，
   *timeout* 將被忽略）。

   POSIX 系统上在 3.0 之前，以及在 Windows 上的所有版本中，如果
   *block* 为真值并且 *timeout* 为 "None"，此操作将进入在底层锁上的不
   可中断的等待。 这意味着不会发生任何异常，特别是 SIGINT 将不会触发
   "KeyboardInterrupt"。

Queue.get_nowait()

   等效於 "get(False)"。

有兩個 method 可以支援追蹤放入佇列的任務是否已由常駐消費者執行緒
(daemon consumer threads) 完全處理。

Queue.task_done()

   表示先前放入佇列的任務已完成。由佇列消費者執行緒使用。對於用來提取
   任務的每個 "get()"，隨後呼叫 "task_done()" 告訴佇列任務的處理已完成
   。

   如果目前 "join()" 阻塞，它將會在所有項目都已處理完畢後恢復（代表對
   於以 "put()" 放進佇列的每個項目，都要收到 "task_done()" 的呼叫）。

   如果呼叫次數超過佇列中放置的項目數量，則引發 "ValueError"。

Queue.join()

   持續阻塞直到佇列中的所有項目都已被獲取並處理完畢。

   当一个条目被添加到队列的时候未完成任务的计数将会增加。 每当一个消费
   者线程调用 "task_done()" 来表明该条目已被提取且其上的所有工作已完成
   时未完成计数将会减少。 当未完成计数降为零时，"join()" 将解除阻塞。

如何等待放入佇列的任務完成的範例：

   import threading
   import queue

   q = queue.Queue()

   def worker():
       while True:
           item = q.get()
           print(f'Working on {item}')
           print(f'Finished {item}')
           q.task_done()

   # Turn-on the worker thread.
   threading.Thread(target=worker, daemon=True).start()

   # Send thirty task requests to the worker.
   for item in range(30):
       q.put(item)

   # Block until all tasks are done.
   q.join()
   print('All work completed')


SimpleQueue 物件
================

"SimpleQueue" 物件提供下面描述的公用 method。

SimpleQueue.qsize()

   傳回佇列的近似大小。注意，qsize() > 0 並不能保證後續的 get() 不會阻
   塞。

SimpleQueue.empty()

   如果队列为空则返回 "True"，否则返回 "False"。 如果 empty() 返回
   "False" 则不保证后续对 get() 的调用将不会阻塞。

SimpleQueue.put(item, block=True, timeout=None)

   將 *item* 放入佇列中。此 method 從不阻塞，並且都會成功（除了潛在的
   低階錯誤，像是分配記憶體失敗）。可選的 args *block* 和 *timeout* 會
   被忽略，它們僅是為了與 "Queue.put()" 相容才存在。

   **CPython 實作細節：** 此 method 有一個可重入 (reentrant) 的 C 實作
   。意思就是，一個 "put()" 或 "get()" 呼叫，可以被同一執行緒中的另一
   個 "put()" 呼叫中斷，而不會造成死鎖 (deadlock) 或損壞佇列中的內部狀
   態。這使得它適合在解構子 (destructor) 中使用，像是 "__del__" method
   或 "weakref" 回呼函式 (callback)。

SimpleQueue.put_nowait(item)

   等效於 "put(item, block=False)"，用於與 "Queue.put_nowait()" 相容。

SimpleQueue.get(block=True, timeout=None)

   從佇列中移除並回傳一個項目。如果可選的 args *block* 為 true，且
   *timeout* 為 "None"（預設值），則在必要時阻塞，直到有可用的項目。如
   果 *timeout* 是正數，則最多會阻塞 *timeout* 秒，如果該時間內沒有可
   用的項目，則會引發 "Empty" 例外。否則（*block* 為 false），如果立即
   可用，則回傳一個項目，否則引發 "Empty" 例外（在這種情況下，
   *timeout* 將被忽略）。

SimpleQueue.get_nowait()

   等效於 "get(False)"。

也參考:

  Class "multiprocessing.Queue"
     用於多行程處理 (multi-processing)（而非多執行緒）情境 (context)
     的佇列 class。

  "collections.deque" 是無界佇列的替代實作，有快速且具原子性 (atomic)
  的 "append()" 和 "popleft()" 操作，這些操作不需要鎖定，並且還支持索
  引。
