目錄
01-3. Process 的生命週期
⏱️ 閱讀時間: 10 分鐘 🎯 難度: ⭐⭐ (簡單)
🎯 本篇重點
理解 Process 從創建到終止的完整生命週期:New → Ready → Running → Waiting → Terminated。
🔄 Process 生命週期五態模型
創建 調度器選中
[New] ──→ [Ready] ──────→ [Running]
↑ │
│ │ I/O 請求
│ ↓
└───────── [Waiting]
完成 I/O
[Running]
│
│ 終止
↓
[Terminated]📋 五種狀態詳解
1. New(新建)
定義: Process 正在被創建,尚未準備好執行。
此時作業系統在做:
- 📝 分配 Process ID (PID)
- 💾 分配記憶體空間(Code, Data, Stack, Heap)
- 📋 創建 Process Control Block (PCB)
- 🔐 設定初始權限和屬性
from multiprocessing import Process
import os
def worker():
print(f"Worker PID: {os.getpid()}")
# 創建 Process(New 狀態)
p = Process(target=worker)
# 此時 Process 已創建,但尚未開始執行
print(f"Process created, state: New")比喻:
- 餐廳接到新訂單(創建 Process)
- 廚房準備食材、器具(分配資源)
- 還沒開始烹飪(尚未執行)
2. Ready(就緒)
定義: Process 已準備好執行,等待 CPU 分配。
特性:
- ✅ 所有資源已分配
- ✅ 已載入記憶體
- ⏳ 等待調度器(Scheduler)分配 CPU
# 啟動 Process(從 New → Ready)
p.start()
print(f"Process ready, waiting for CPU")
# Process 進入 Ready Queue(就緒佇列)Ready Queue:
Ready Queue(就緒佇列)
┌─────────────────────────────┐
│ Process A │ Process B │ ... │ → 等待 CPU
└─────────────────────────────┘
↑
新的 Process 加入比喻:
- 食材準備好了(資源就緒)
- 廚師在等爐子空出來(等待 CPU)
- 多個訂單排隊等候(Ready Queue)
3. Running(執行中)
定義: Process 正在使用 CPU 執行指令。
特性:
- ✅ 獲得 CPU 時間
- ✅ 正在執行程式碼
- ⚠️ 同一時刻,一個 CPU 核心只能執行一個 Process
def worker():
print("開始執行...") # Running 狀態
for i in range(1000000):
result = i * i # CPU 密集運算
print("執行完成")CPU 調度:
時間軸:
0ms - 50ms: Process A Running
50ms - 100ms: Process B Running
100ms - 150ms: Process A Running
150ms - 200ms: Process C Running比喻:
- 廚師正在炒菜(Process 執行中)
- 爐子一次只能用一個鍋(單核 CPU)
- 可能隨時被打斷換另一道菜(Context Switch)
4. Waiting(等待)
定義: Process 等待某個事件發生(I/O、鎖、信號等)。
常見等待原因:
- 💾 I/O 操作:讀寫檔案、網路請求
- 🔒 鎖:等待其他 Process 釋放資源
- ⏰ 睡眠:time.sleep()
- 📡 信號:等待其他 Process 的通知
import time
import requests
def worker():
print("Running: 開始執行")
# 進入 Waiting 狀態(I/O 操作)
print("Waiting: 讀取檔案...")
with open('data.txt', 'r') as f:
data = f.read()
# 返回 Ready 狀態
print("Ready: I/O 完成,等待 CPU")
# 再次進入 Running 狀態
print("Running: 處理資料...")
result = process_data(data)
# 又進入 Waiting 狀態(網路請求)
print("Waiting: 呼叫 API...")
response = requests.get('https://api.example.com')
# 返回 Ready → Running
print("Running: 完成")Waiting Queue:
Waiting Queue(等待佇列)
┌──────────────────────────────────────┐
│ Process A (等待磁碟 I/O) │
│ Process B (等待網路回應) │
│ Process C (等待鎖釋放) │
└──────────────────────────────────────┘
↓ I/O 完成
移回 Ready Queue比喻:
- 廚師在等水燒開(I/O 等待)
- 這期間可以去做其他菜(CPU 執行其他 Process)
- 水開了會通知廚師(中斷,返回 Ready)
5. Terminated(終止)
定義: Process 執行完畢或被強制終止。
終止原因:
- ✅ 正常終止:程式執行完畢
- ❌ 異常終止:錯誤、異常
- 🔫 被殺死:kill 指令、記憶體不足
def worker():
try:
print("執行任務...")
# 正常執行
result = do_work()
print("正常終止")
except Exception as e:
print(f"異常終止: {e}")
finally:
# 清理資源
cleanup()
p = Process(target=worker)
p.start()
p.join() # 等待 Process 終止
# Process 進入 Terminated 狀態
print(f"Process terminated, exit code: {p.exitcode}")作業系統清理:
Process 終止
↓
回收記憶體空間
↓
關閉檔案描述符
↓
釋放系統資源
↓
從 Process 表中移除
↓
完全終止比喻:
- 菜做完了上菜(正常終止)
- 廚房收拾乾淨(資源回收)
- 訂單結案(Process 移除)
🔄 完整生命週期範例
Python 實戰案例
from multiprocessing import Process
import os
import time
import requests
def complete_lifecycle():
pid = os.getpid()
print(f"[{pid}] Running: Process 開始執行")
# Running → Waiting(磁碟 I/O)
print(f"[{pid}] Waiting: 讀取檔案...")
time.sleep(1) # 模擬 I/O
# Waiting → Ready → Running
print(f"[{pid}] Running: 處理資料...")
for i in range(1000000):
_ = i * i # CPU 運算
# Running → Waiting(睡眠)
print(f"[{pid}] Waiting: 睡眠 2 秒...")
time.sleep(2)
# Waiting → Ready → Running
print(f"[{pid}] Running: 完成任務")
# Running → Terminated
if __name__ == '__main__':
# New: 創建 Process
p = Process(target=complete_lifecycle)
print(f"[Main] New: Process 創建")
# New → Ready
p.start()
print(f"[Main] Ready: Process 已啟動")
# 等待 Process 終止
p.join()
# Terminated
print(f"[Main] Terminated: Process 終止,exit code = {p.exitcode}")輸出:
[Main] New: Process 創建
[Main] Ready: Process 已啟動
[12345] Running: Process 開始執行
[12345] Waiting: 讀取檔案...
[12345] Running: 處理資料...
[12345] Waiting: 睡眠 2 秒...
[12345] Running: 完成任務
[Main] Terminated: Process 終止,exit code = 0📊 狀態轉換總結
所有可能的狀態轉換
1. New → Ready
• Process 創建完成,準備執行
2. Ready → Running
• 調度器分配 CPU 給 Process
3. Running → Ready
• 時間片用完(Time Slice Expired)
• 被高優先級 Process 搶佔(Preemption)
4. Running → Waiting
• I/O 請求(檔案、網路)
• 等待鎖、信號
• 睡眠(sleep)
5. Waiting → Ready
• I/O 完成
• 鎖釋放
• 睡眠結束
6. Running → Terminated
• Process 正常結束
• Process 異常終止
• 被殺死(kill)不可能的轉換
❌ Waiting → Running(必須先進入 Ready) ❌ New → Running(必須先進入 Ready) ❌ Terminated → 任何狀態(Process 已終止)
🔍 查看 Process 狀態
Linux 查看
# 查看所有 Process 的狀態
ps aux
# 輸出:
USER PID STAT COMMAND
john 1234 R python server.py # R = Running
john 1235 S python worker.py # S = Sleeping (Waiting)
john 1236 Z python old.py # Z = Zombie (Terminated)狀態代碼:
R(Running):執行中或就緒S(Sleeping):可中斷的睡眠(Waiting)D(Uninterruptible Sleep):不可中斷的睡眠Z(Zombie):殭屍 Process(已終止但未回收)T(Stopped):已停止
Python 查看
import psutil
import os
def check_process_status():
process = psutil.Process(os.getpid())
print(f"PID: {process.pid}")
print(f"狀態: {process.status()}")
print(f"CPU 時間: {process.cpu_times()}")
print(f"記憶體: {process.memory_info().rss / 1024 / 1024:.2f} MB")
check_process_status()可能的狀態:
'running' # Running
'sleeping' # Waiting
'zombie' # Terminated (未回收)
'stopped' # 已停止⚠️ 特殊狀態:Zombie Process(殭屍進程)
什麼是 Zombie?
定義: Process 已終止,但父 Process 尚未讀取其退出狀態。
from multiprocessing import Process
import time
import os
def child_process():
print(f"子 Process {os.getpid()} 執行中...")
time.sleep(1)
print("子 Process 結束")
# 子 Process 終止,成為 Zombie
def parent_process():
p = Process(target=child_process)
p.start()
# 父 Process 不呼叫 join(),繼續執行
print("父 Process 繼續執行...")
time.sleep(10) # 子 Process 成為 Zombie 10 秒
# 呼叫 join() 回收子 Process
p.join()
print("子 Process 已回收")
parent_process()查看 Zombie:
ps aux | grep Z
# 輸出:
john 1237 Z 0:00 [python] <defunct>解決方法:
- ✅ 父 Process 呼叫
join()或wait() - ✅ 使用信號處理器自動回收
✅ 重點回顧
Process 五種狀態:
| 狀態 | 說明 | 特徵 |
|---|---|---|
| New | 正在創建 | 分配資源 |
| Ready | 等待 CPU | 已就緒,排隊中 |
| Running | 執行中 | 使用 CPU |
| Waiting | 等待事件 | I/O、鎖、睡眠 |
| Terminated | 已終止 | 回收資源 |
關鍵理解:
- ✅ Process 在生命週期中不斷切換狀態
- ✅ Running ↔ Waiting 是最頻繁的切換
- ✅ I/O 密集應用大部分時間在 Waiting
- ✅ CPU 密集應用大部分時間在 Running/Ready
- ✅ 避免 Zombie Process(記得回收)
上一篇: 01-2. Process 的組成 下一篇: 01-4. Context Switch 詳解
最後更新:2025-01-04