# tqdm
[](https://hackmd.io/@RogelioKG/tqdm)
### 參考
+ 🔗 [**Github : source code**](https://github.com/tqdm/tqdm)
+ 🔗 [**clay-atlas**](https://clay-atlas.com/blog/2019/11/11/python-chinese-tutorial-tqdm-progress-and-ourself/)
+ 🔗 [**StackOverflow : Fix jumping of multiple progress bars (tqdm) in python multiprocessing**](https://stackoverflow.com/questions/56665639/fix-jumping-of-multiple-progress-bars-tqdm-in-python-multiprocessing)
### 注意
|🚨 <span class="caution">CAUTION</span>|
|:---|
|使用 for-loop 迭代的進度條是不會有 context management 的。|
|📗 <span class="tip">TIP</span>|
|:---|
|在極大量 total 且 update 又非常少量的情況下,<br />狀態不會實時 output (只會間斷性 output)。<br />未進行 output 的 update 耗時為 600 ns;<br />進行 output 的 update 耗時為 400 us (666 倍)。<br />而 `disable=True` 能遏止 output。<br />(如果不需要輸出的話,可以考慮關掉,雖然它通常不怎麼佔性能開銷)|
### 參數 (`tqdm`)
```py
iterable: Iterable[int] # 迭代器
desc: str # 進度條敘述
total: float # 進度條總量 (☢️ 若 iterable 為產生器,需指定總量才會顯示進度條)
leave: bool # 結束後,進度條是否留在輸出
ncols: int # 進度條使用幾行空間
mininterval: float = 0.1, # 最小更新時間區間 (0.1s)
maxinterval: float = 10, # 最大更新時間區間 (10s)
ascii: bool | str # True 的話就使用 ascii
# 或者你也可以給 str
# 預設是 " 123456789#"
# 翻譯蒟蒻:未完成顯示 " ",已完成顯示 "#",一格之間分成9種進度,看刷新的時候跑到哪,決定顯示哪個數字
disable: bool = False # 不顯示
unit: str = "it", # 單位
unit_scale: bool = False, # 單位自動縮放
bar_format: str # 自訂進度條格式 (會影響性能)
initial: float = 0, # 一開始就跑到幾%
unit_divisor: float = 1000, # 單位換算 (如果你有指定單位自動縮放)
colour: str # 進度條顏色
delay: float = 0, # 開頭不顯示幾秒
```
### 方法 (`tqdm`)
| method | description |
| ------ | ----------- |
| `close()` | 關閉進度條,清理其資源。 |
| `clear(nolock=False)` | 從螢幕上移除進度條,通常在多個進度條之間切換時使用。 |
| `refresh(nolock=False)` | 強制刷新進度條,立即顯示當前進度。 |
| `reset(total=None)` | 重置進度條,並可以選擇性地設置新的總步數。 |
| `update(n=1)` | 將進度條增加 `n` 步 (預設為 1)。 |
| `set_description(desc=None, refresh=True)` | 設置進度條的新描述,並可選擇是否刷新顯示。 |
| `set_description_str(desc=None, refresh=True)` | 類似於 `set_description`,但直接接受字串來設置描述。 |
| `set_postfix(ordered_dict=None, refresh=True, **kwargs)` | 設置後綴字串,允許在進度條上顯示自定義信息。 |
| `set_postfix_str(s='', refresh=True)` | 類似於 `set_postfix`,但直接接受字串來設置後綴。 |
| `write(s, file=None, end='\n', nolock=False)` | 將字串 `s` 寫入輸出檔案 (預設為 `sys.stdout`),跳過進度條的顯示。 |
| `format_meter(...)` | 用於格式化進度條顯示的工具方法。 |
| `display(msg=None, pos=None, nolock=False)` | 渲染進度條,並可選擇性地顯示消息 `msg`。 |
| `unpause()` | 恢復被暫停的進度條。 |
| `update_to(n)` | 手動將進度條設置為 `n` 步,並相應地更新。 |
| `reset_pbar()` | 重置與進度條顯示相關的內部變量。 |
| `last_print_n()` | 返回進度條最後一次打印的位置,以 `n` 的形式表示。 |
| `last_print_t()` | 返回進度條最後一次打印的時間戳。 |
| `ema()` | 返回速率的指數移動平均值。 |
| `start_t` | 返回進度條的開始時間。 |
| `n` | 返回進度條的當前步數。 |
| `total` | 返回進度條的總步數。 |
| `sp` | 返回進度條的簡短描述 (通常顯示在終端中)。 |
| `desc` | 返回進度條的描述。 |
| `unit` | 返回進度條的計量單位 (預設為 'it')。 |
| `rate` | 返回當前的進度速率。 |
| `format_interval(t)` | 格式化時間間隔 `t` 的工具方法。 |
| `format_num(n)` | 格式化數字 `n` 的工具方法。 |
### 多進程進度條
1. 讓每個 children process 都有一個 worker_id (從 1 開始,不重複)
2. 同時 worker_id 也作為 children process 進度條的 position (每個 process 都待在自己位置)
3. 對 children process 進度條使用 leave=False 讓輸出保持乾淨 (留著會導致輸出錯位)
4. 讓 main process 負責管理總進度條
5. 要上輸出鎖 (同一時間只能有一個 update,沒鎖可能導致輸出錯位)
```py
import time
import random
from multiprocessing import get_context, current_process
from tqdm import tqdm
def progresser(n: int) -> int:
counts = 100
worker_id = current_process()._identity[0]
with tqdm(
total=counts,
desc=f"#{n} on worker {worker_id}",
position=worker_id,
ascii=" ▯▮",
leave=False,
) as pbar:
for _ in range(counts):
pbar.update(1)
time.sleep(random.uniform(0, 0.05))
return n
if __name__ == "__main__":
# 進程啟動方法: spawn
context = get_context("spawn")
# 輸出鎖
output_lock = context.RLock()
tqdm.set_lock(output_lock)
numbers = [*range(100)]
with context.Pool(
processes=10, initializer=tqdm.set_lock, initargs=(output_lock,)
) as pool:
with tqdm(total=len(numbers), desc=f"TOTAL", ascii=" ▯▮") as pbar:
results = pool.imap(progresser, numbers)
for result in results:
pbar.update(1)
```