iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0

前言:進度顯示只是印個百分比,需要特別設計嗎?

單一個下載工作,print 一下進度確實夠用。但當有十個片段同時並行下載,每個片段各自 print 自己的進度,終端機畫面會變成一團交錯覆蓋、無法閱讀的文字流,反而看不出整體進度到哪。

今日目標

  • 認識並行工作的進度回報,跟單一工作的進度回報是不同的問題
  • 看一組「各自直接 print vs 統一格式化輸出」的對照
  • 理解把「輸出格式」跟「呼叫端邏輯」分開的價值

❌ vs ✅:各自直接 print vs 統一的進度輸出介面

❌ 反例:每個工作各自直接印

async def save_segment(index, total):
    print(f"downloading {index}/{total}")  # 十個並行工作各自印,互相干擾

✅ 正例:統一的進度條輸出函式,格式一致、可控制輸出方式

def progressbar(size: int, total: int, title: str = "Progress"):
    filled = int(size * 20 / total)
    bar = '█' * filled + ' ' * (20 - filled)
    print(f'\r[{title}]:[{bar}]{size / total * 100:.2f}%', end='')

async def save_segment(index, total, directory):
    progressbar(index, total, f'download: {directory}')

把輸出邏輯收斂成一個共用函式,好處不只是格式一致——它讓「進度怎麼呈現」變成一個可以獨立替換的實作:現在是印到終端機,之後如果要改成寫進日誌檔、丟到某個監控系統,只需要換掉 progressbar 這個函式的實作,呼叫端完全不用改。

Logger 抽象:把「輸出什麼」跟「怎麼輸出」分開

同樣的道理也適用在錯誤與警告訊息上。與其在程式碼各處直接 print,統一透過一個 Logger 類別(區分 info/warning/error/success 等等級,各自對應不同顏色或格式)來輸出,好處是呼叫端只需要表達「這是一則什麼等級的訊息」,不需要關心這則訊息最後會被印成什麼樣子。這也讓測試變得容易——測試時可以換一個假的 Logger 實作,只驗證「有沒有記錄到某則訊息」,不用真的去解析終端機輸出的文字。

今日思考題

你的專案裡的進度/日誌輸出,是每個地方各自直接 print,還是有一層統一的抽象?如果現在要把輸出方式從終端機改成寫進檔案,你要改幾個地方?

今日重點回顧

  • 並行工作的進度回報,各自直接輸出會互相干擾,需要統一格式化
  • 把輸出邏輯收斂成共用函式/類別,讓「呈現方式」可以獨立替換
  • 統一的 Logger 抽象也讓測試更容易,不用解析真實輸出內容

明日預告

明天回到重試策略:失敗要退避重試,但退避的時間該怎麼選。


上一篇
Day 17:ThreadPoolExecutor 包 asyncio coroutine——一個混用兩種併發模型的權宜設計
下一篇
Day 19:失敗要退避重試,但退避策略怎麼選
系列文
下載器不是寫完就能跑:一個 HLS 分段式串流工具的架構與測試修練 共 21 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言