
想要讓程式跑得更快,大家直覺都會想到:「讓它同時做很多事!」(並發)。但在 Python 中,這件事比其他語言稍微複雜一點,因為有一個著名的大魔王——GIL (Global Interpreter Lock,全域直譯器鎖)。
1. 什麼是 GIL?
GIL 是 CPython (標準 Python 直譯器) 的一個機制,它確保同一時間只有一個執行緒 (Thread) 在執行 Python Bytecode。
這意味著:即使你的電腦有 16 核心 CPU,Python 的多執行緒程式在任何瞬間其實只在運用 1 個核心。
那多執行緒在 Python 中是不是廢了?不!這取決於你的任務類型:
- I/O 密集型 (I/O-bound):爬蟲、讀寫檔案、資料庫。等待硬碟或網路回應時,執行緒會釋放 GIL,適合用 Threading。
- CPU 密集型 (CPU-bound):影像處理、加密運算、矩陣計算。一直佔用 CPU,Threading 反而因為切換 Context 變慢,必須用 Multiprocessing。
2. Threading:適合 I/O 任務
模擬一個 I/O 任務 (例如下載網頁)。
import threading
import time
def download_page(url):
print(f"開始下載 {url}...")
time.sleep(1) # 模擬網路延遲
print(f"下載完成 {url}")
start = time.time()
threads = []
urls = ["Page1", "Page2", "Page3"]
for url in urls:
t = threading.Thread(target=download_page, args=(url,))
threads.append(t)
t.start()
# 等待所有執行緒完成
for t in threads:
t.join()
end = time.time()
print(f"總花費時間: {end - start:.2f} 秒")
執行結果約為 1.0x 秒。如果是依序執行,則需要 3 秒。Threading 在這裡大獲全勝!
3. Multiprocessing:適合 CPU 任務
模擬一個 CPU 運算任務。
import time
from multiprocessing import Process
def heavy_computation(n):
# 瘋狂運算,吃滿 CPU
count = 0
for i in range(n):
count += 1
N = 50000000
if __name__ == '__main__': # Windows/Mac 上必須加這行保護
start = time.time()
p1 = Process(target=heavy_computation, args=(N,))
p2 = Process(target=heavy_computation, args=(N,))
p1.start()
p2.start()
p1.join()
p2.join()
end = time.time()
print(f"多進程花費時間: {end - start:.2f} 秒")
Multiprocessing 會啟動獨立的 Python 進程 (Process),每個進程有自己的 Python 直譯器和記憶體空間,因此不受 GIL 限制,能真正利用多核心。
如果是用 threading 跑這個 CPU 任務,時間反而會比單執行緒還慢 (因為 GIL 爭奪戰)!
4. concurrent.futures:現代化的寫法
Python 3.2+ 提供了更高階的介面 ThreadPoolExecutor 和 ProcessPoolExecutor,寫法更簡單統一。
from concurrent.futures import ThreadPoolExecutor
urls = ["Page1", "Page2", "Page3"]
def download_page(url):
time.sleep(1)
return f"{url} Data"
with ThreadPoolExecutor(max_workers=3) as executor:
# map 會自動分配任務並收集結果
results = executor.map(download_page, urls)
for res in results:
print(res)
5. 總結
| 特性 | Threading (多執行緒) | Multiprocessing (多進程) |
|---|---|---|
| 記憶體 | 共享 (省記憶體) | 獨立 (耗記憶體) |
| GIL 影響 | 受限制 | 不受限制 |
| 適用場景 | I/O 密集型 (爬蟲、Web) | CPU 密集型 (AI、計算) |
| 切換成本 | 低 | 高 |
下一章,我們將介紹 Python 並發程式設計的最新潮流——AsyncIO (非同步 I/O),這是寫出高效能 Web Server (如 FastAPI) 的基礎!
延伸閱讀: