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

0%