---
# System prepended metadata

title: queue
tags: [Python, Multitasking, Python's Flying Circus]

---

# queue

[![RogelioKG/queue](https://img.shields.io/badge/Sync%20with%20HackMD-grey?logo=markdown)](https://hackmd.io/@RogelioKG/queue)

### 說明
專為多線程中 multiple producers & consumers 場景設計的佇列

### 常用
+ **類別**
  | class             | description      |
  | ----------------- | ---------------- |
  | `Queue()`         | 同步先進先出佇列 |
  | `PriorityQueue()` | 同步優先佇列     |
  | `LifoQueue()`     | 同步後進後出佇列 |

+ **方法**
  | method               | description                                                                                                         |
  | -------------------- | ------------------------------------------------------------------------------------------------------------------- |
  | `qsize()`            | 返回佇列的大小                                                                                                      |
  | `empty()`            | 如果佇列為空，返回 `True`，反之返回 `False`                                                                         |
  | `full()`             | 如果佇列滿了，返回 `True`，反之返回 `False`                                                                         |
  | `get(block,timeout)` | 取出佇列的項目，`timeout` 可指定等待時間                                                                            |
  | `get_nowait()`       | 等於 `get(block=False)`，因為是非 blocking 操作，線程若無法獲取元素時，不會進入等待狀態。反之，此函數 `raise Full`  |
  | `put(item)`          | 放入佇列的項目，`timeout` 可指定等待時間                                                                            |
  | `put_nowait(item)`   | 等於 `put(item, False)`，因為是非 blocking 操作，線程若無法放入元素時，不會進入等待狀態。反之，此函數 `raise Empty` |
  | `task_done()`        | 在 consumer 完成一項工作之後，向佇列發送一個工作已經完成的訊號                                                                |
  | `join()`             | 等待所有的工作完成之後，再繼續執行 (註：【佇列為空】是【所有工作完成】的必要非充分條件)                             |

### 工作完成
  > 很多時候你會遇到這種要求：「確定資料都已經由 consumer 處理完畢，\
  > 而非單純佇列為空 (說不定資料只是拿走，consumer 還沒處理完)。\
  > 因為資料必須處理完畢，其他工作才能拿這些完整的已處理資料進行下一步作業」\
  > 這個時候我們就需要多一個條件變數，來判斷被 consumer 拿走的資料是否皆已處理完畢。

  ```py
  def task_done(self):
      with self.all_tasks_done:
          unfinished = self.unfinished_tasks - 1
          if unfinished <= 0:
              if unfinished < 0:
                  raise ValueError('task_done() called too many times')
              self.all_tasks_done.notify_all() # unfinished == 0，資料皆已處理完畢，在等資料的線程們，你們可以做事了！
          self.unfinished_tasks = unfinished
  ```
  ```py
  def join(self):
      with self.all_tasks_done:
          while self.unfinished_tasks:
              self.all_tasks_done.wait() # 等待 consumer 將資料處理完畢的線程
  ```