01-7. Worker 如何選擇

⏱️ 閱讀時間: 8 分鐘 🎯 難度: ⭐⭐⭐ (重要!面試必考)


🎯 本篇重點

這是基礎篇最重要的一篇!學會如何根據應用特性選擇正確的 Worker 類型。


⚠️ 新專案?先看這裡!

如果你正在開始一個新的 Django 專案(Django 3.0+),強烈建議直接使用現代的 ASGI 方案:

# 現代推薦方案(新專案)
pip install uvicorn[standard]

# 開發環境
uvicorn myproject.asgi:application --reload

# 生產環境
uvicorn myproject.asgi:application --workers 4 --host 0.0.0.0 --port 8000

為什麼?

  • ✅ Python 官方異步標準(asyncio)
  • ✅ Django 3.0+ 原生支持 async views
  • ✅ 更好的生態系統和長期支持
  • ✅ 不需要 Monkey Patching
  • ✅ 更清晰的 async/await 語法

本篇討論的 Gunicorn Workers 主要適用於:

  • 維護舊的 WSGI Django 專案(Django < 3.0)
  • 暫時無法遷移到 ASGI 的專案
  • 混合 WSGI/ASGI 的過渡期

📊 四種方案完整對比

核心特性對比(含現代方案)

特性ASGI (Uvicorn)GeventGthreadSync
技術狀態🆕 現代推薦⚠️ 舊專案維護⚠️ 過渡方案✅ 穩定可靠
Django 支持3.0+ 原生WSGI onlyWSGI onlyWSGI 標準
並發模型進程 + asyncio進程 + 協程進程 + 線程進程
單 Worker 並發數千+1000+threads 數1
語法async/await同步風格同步同步
Monkey Patch❌ 不需要⚠️ 必須❌ 不需要❌ 不需要
CPU 密集型⚠️ 可用❌ 差⚠️ 受 GIL 限制✅ 優秀
I/O 密集型✅ 優秀✅ 優秀✅ 良好❌ 浪費
混合型任務✅ 優秀⚠️ 可用✅ 優秀⚠️ 可用
長期維護✅ 推薦⚠️ 技術債務✅ 可接受✅ 穩定
複雜度⭐⭐⭐ 需學習 async⭐⭐⭐ 複雜⭐⭐ 中等⭐ 簡單
除錯難度⭐⭐⭐ 中等⭐⭐⭐⭐ 困難⭐⭐ 中等⭐ 容易

效能對比(實測數據)

測試場景:1000 個請求

1. 快速請求(< 10ms)
├─ Sync:    2500 req/s  ⭐⭐⭐⭐⭐
├─ Gthread: 2200 req/s  ⭐⭐⭐⭐
└─ Gevent:  2000 req/s  ⭐⭐⭐⭐

2. I/O 密集(外部 API,1 秒)
├─ Sync:    4 req/s     ⭐
├─ Gthread: 40 req/s    ⭐⭐⭐
└─ Gevent:  500 req/s   ⭐⭐⭐⭐⭐

3. CPU 密集(複雜計算)
├─ Sync:    100 req/s   ⭐⭐⭐⭐⭐
├─ Gthread: 80 req/s    ⭐⭐⭐
└─ Gevent:  50 req/s    ⭐⭐

4. 混合型(I/O + CPU)
├─ Sync:    26 req/s    ⭐⭐
├─ Gthread: 106 req/s   ⭐⭐⭐⭐⭐
└─ Gevent:  142 req/s   ⭐⭐⭐⭐

🌳 決策樹

完整決策流程(2025 年版)

開始
  │
  ├─ 這是新專案嗎?(Django 3.0+)
  │  │
  │  ├─ YES → 直接用 ASGI (Uvicorn) ✅ 🆕
  │  │        pip install uvicorn[standard]
  │  │        uvicorn myproject.asgi:application --workers 4
  │  │
  │  │        理由:
  │  │        • Python 官方標準
  │  │        • Django 原生支持 async views
  │  │        • 更好的長期維護
  │  │
  │  └─ NO(舊專案/WSGI)→ 繼續下方決策
  │
  ├─ 應用主要做什麼?
  │
  ├─ CPU 密集(大量計算)?
  │  └─ YES → 用 Sync Worker ✅
  │           配置:workers = CPU_cores
  │
  ├─ I/O 密集(大量等待)?
  │  │
  │  ├─ 並發需求 > 500 且無法遷移到 ASGI?
  │  │  └─ YES → 用 Gevent Worker ⚠️ (考慮遷移到 ASGI)
  │  │           配置:workers = CPU × 2 + 1
  │  │                 worker-connections = 1000
  │  │
  │  └─ 並發需求 < 500?
  │     └─ 用 Gthread Worker ✅
  │              配置:workers = CPU × 2 + 1
  │                    threads = 2-4
  │
  └─ 混合型(I/O + CPU)?
     └─ 用 Gthread Worker ✅
              配置:workers = CPU × 2 + 1
                    threads = 4

🎯 按場景選擇

場景 1:內容管理系統(CMS)

# 特點:
# - CRUD 操作為主
# - 資料庫查詢多
# - 並發不高(< 100)
# - 請求快速(< 100ms)

# 範例:
def create_post(request):
    post = Post.objects.create(
        title=request.POST['title'],
        content=request.POST['content'],
        author=request.user
    )
    return JsonResponse({'id': post.id})

推薦:Sync Worker

gunicorn myproject.wsgi:application \
    --workers 9 \
    --worker-class sync \
    --timeout 30

理由:

  • ✅ 請求快速,不浪費資源
  • ✅ 簡單可靠
  • ✅ 並發需求低
  • ✅ 除錯容易

場景 2:API 聚合服務

# 特點:
# - 呼叫多個外部 API
# - 大量 I/O 等待
# - 並發高(> 500)
# - 每個請求 1-3 秒

# 範例:
def dashboard(request):
    # 呼叫 5 個外部 API
    weather = requests.get('https://api.weather.com')
    news = requests.get('https://api.news.com')
    stocks = requests.get('https://api.stocks.com')
    social = requests.get('https://api.twitter.com')
    analytics = requests.get('https://api.analytics.com')
    
    return JsonResponse({...})

推薦:Gevent Worker

pip install gevent

gunicorn myproject.wsgi:application \
    --workers 4 \
    --worker-class gevent \
    --worker-connections 1000 \
    --timeout 60
# gunicorn_config.py
import gevent.monkey
gevent.monkey.patch_all()

理由:

  • ✅ 大量 I/O 等待,協程最適合
  • ✅ 高並發(4 × 1000 = 4000)
  • ✅ 充分利用等待時間
  • ✅ 記憶體效率高

場景 3:電商網站

# 特點:
# - 資料庫查詢 + 業務邏輯計算
# - 中等並發(100-500)
# - 混合型任務
# - 需要穩定可靠

# 範例:
def checkout(request):
    # I/O:查詢資料庫
    cart = Cart.objects.get(user=request.user)
    products = cart.products.all()
    
    # CPU:計算折扣
    discount = calculate_discount(products, request.user)
    
    # CPU:計算運費
    shipping = calculate_shipping(cart.address)
    
    # I/O:創建訂單
    order = Order.objects.create(...)
    
    # I/O:發送通知
    send_order_email(order)
    
    return JsonResponse({'order_id': order.id})

推薦:Gthread Worker

gunicorn myproject.wsgi:application \
    --workers 9 \
    --worker-class gthread \
    --threads 4 \
    --timeout 30

理由:

  • ✅ 平衡 I/O 和 CPU
  • ✅ 並發數適中(9 × 4 = 36)
  • ✅ 不需要 Monkey Patch
  • ✅ 穩定可靠

場景 4:數據分析平台

# 特點:
# - 大量 CPU 計算
# - 處理大數據集
# - 並發低(< 50)
# - 每個請求耗時長

# 範例:
def analyze_data(request):
    file = request.FILES['data']
    df = pd.read_csv(file)
    
    # 複雜的數據分析
    result = df.groupby('category').agg({
        'sales': ['sum', 'mean', 'std'],
        'profit': ['sum', 'mean']
    })
    
    # 生成報告
    report = generate_report(result)
    
    return JsonResponse(report)

推薦:Sync Worker

gunicorn myproject.wsgi:application \
    --workers 4 \
    --worker-class sync \
    --timeout 300 \
    --max-requests 100

理由:

  • ✅ CPU 密集,多進程可並行
  • ✅ Workers = CPU 核心數
  • ✅ 不受 GIL 限制
  • ✅ 簡單可靠

場景 5:即時聊天系統

# 特點:
# - WebSocket 長連接
# - 超高並發(> 1000)
# - 主要是等待和轉發消息
# - 需要保持連接

# 範例:
def chat_stream(request):
    def event_stream():
        while True:
            message = get_new_message(request.user)
            if message:
                yield f"data: {message}\n\n"
            gevent.sleep(0.1)
    
    return StreamingHttpResponse(event_stream())

推薦:Gevent Worker + Django Channels

pip install gevent channels

gunicorn myproject.wsgi:application \
    --workers 4 \
    --worker-class gevent \
    --worker-connections 2000 \
    --timeout 0

理由:

  • ✅ 長連接,協程最適合
  • ✅ 超高並發(4 × 2000 = 8000)
  • ✅ 連接保持,不佔用資源
  • ✅ 記憶體效率極高

場景 6:爬蟲服務

# 特點:
# - 批量抓取網頁
# - 大量網絡請求
# - 並發極高(> 1000)
# - I/O 密集

# 範例:
def scrape_websites(request):
    urls = request.POST.getlist('urls')  # 100+ URLs
    
    import gevent
    from gevent import monkey
    monkey.patch_all()
    
    jobs = [gevent.spawn(fetch_url, url) for url in urls]
    gevent.joinall(jobs)
    
    results = [job.value for job in jobs]
    return JsonResponse({'results': results})

推薦:Gevent Worker

gunicorn myproject.wsgi:application \
    --workers 8 \
    --worker-class gevent \
    --worker-connections 2000 \
    --timeout 300

理由:

  • ✅ 極高並發(8 × 2000 = 16000)
  • ✅ 網絡請求密集
  • ✅ 充分利用等待時間
  • ✅ 記憶體占用低

場景 7:微服務 API

# 特點:
# - RESTful API
# - 服務間 RPC 呼叫
# - 中等並發(200-500)
# - 混合 I/O 和計算

# 範例:
def user_service(request):
    # RPC 呼叫其他服務
    orders = requests.get(f'{ORDER_SERVICE}/orders?user={user_id}')
    payments = requests.get(f'{PAYMENT_SERVICE}/history?user={user_id}')
    
    # 計算統計
    stats = calculate_user_stats(orders, payments)
    
    return JsonResponse(stats)

推薦:Gthread Worker

gunicorn myproject.wsgi:application \
    --workers 9 \
    --worker-class gthread \
    --threads 4 \
    --timeout 60

理由:

  • ✅ 平衡並發能力
  • ✅ 混合型任務
  • ✅ 穩定可靠
  • ✅ 適合微服務架構

📋 快速選擇表

首要決策:新專案 vs 舊專案

專案類型Django 版本推薦方案理由
新專案Django 3.0+ASGI (Uvicorn) 🆕Python 官方標準,長期支持
舊專案Django < 3.0Gunicorn Workers需要逐步遷移到 ASGI
過渡期Django 3.0+Gthread → ASGI平滑遷移路徑

按任務類型選擇(舊專案/WSGI)

任務類型特徵推薦方案配置
新專案(任何類型)Django 3.0+ASGI (Uvicorn)workers = 4
CPU 密集計算、數據分析Syncworkers = CPU
I/O 密集(低並發)API 呼叫、< 500 並發Gthreadworkers × threads
I/O 密集(高並發)API 呼叫、> 500 並發Gevent ⚠️ 或遷移 ASGIworkers × 1000
混合型CRUD + 計算 + APIGthreadworkers × 4
長連接WebSocket、SSEASGI (Daphne)原生支持
簡單 CRUD內容管理、後台Syncworkers = CPU × 2 + 1

按並發需求選擇

並發需求推薦方案配置示例
< 50Sync (4 workers)4 個並發
50-200Gthread (9 workers × 2 threads)18 個並發
200-500Gthread (9 workers × 4 threads)36 個並發
500-2000Gevent (4 workers × 1000)4000 個並發
> 2000Gevent (8 workers × 2000)16000 個並發

按應用類型選擇

應用類型Worker理由
CMS / 部落格Sync簡單可靠
電商網站Gthread混合任務
API 網關Gevent高並發 I/O
數據分析SyncCPU 密集
即時通訊Gevent長連接
後台管理Sync低並發
微服務Gthread服務間通訊
爬蟲服務Gevent大量網絡請求

🎤 面試高頻問題

Q1: 如何快速判斷用哪種 Worker?

完整答案:

我會問自己三個問題:

1. 應用主要在做什麼?

  • 計算 → Sync
  • 等待(API、資料庫)→ Gevent 或 Gthread
  • 混合 → Gthread

2. 並發需求有多高?

  • < 50 → Sync
  • 50-500 → Gthread
  • 500 → Gevent

3. 每個請求多久?

  • < 100ms → Sync
  • 100ms-1s → Gthread
  • 1s → Gevent

舉例: 如果是電商網站,有資料庫查詢、業務計算、可能呼叫支付 API,並發約 200 個,我會選擇 Gthread Worker,配置 9 workers × 4 threads = 36 並發。


Q2: 什麼情況下不能用 Gevent?

完整答案:

以下情況不適合使用 Gevent:

1. CPU 密集型任務

  • 協程無法利用多核
  • 一個計算密集的請求會阻塞其他協程
  • 例如:數據分析、機器學習推理

2. 不兼容 Monkey Patch 的庫

  • 某些 C 擴展庫無法被 Patch
  • 例如:某些資料庫驅動、加密庫
  • 需要檢查兼容性

3. 團隊不熟悉協程

  • 除錯困難
  • 學習成本高
  • 維護成本大

4. 需要真正的多線程

  • 某些場景需要原生線程
  • Gevent 的「協程」不是真正的線程

這些情況應該選擇 SyncGthread Worker。


Q3: 給你一個新專案,你會如何選擇 Worker?

完整答案:

我會按照以下步驟評估:

Step 1:分析應用特性(5 分鐘)

# 統計代碼中的操作比例
CPU 操作計算處理):20%
I/O 操作資料庫API):70%
其他10%

Step 2:預估並發需求(10 分鐘)

  • 預期用戶數:1000 人
  • 同時在線:100 人
  • 並發請求:50 個

Step 3:選擇 Worker(1 分鐘)

  • I/O 佔 70% → 排除 Sync
  • 並發 50 個 → Gthread 或 Gevent
  • 混合型任務 → 選擇 Gthread

Step 4:初始配置

gunicorn myproject.wsgi:application \
    --workers 9 \
    --worker-class gthread \
    --threads 4
# 總並發:36 個

Step 5:壓力測試調整(1 小時)

  • 使用 locust 或 ab 測試
  • 調整 workers 和 threads
  • 找到最佳配置

Step 6:監控生產環境(持續)

  • 觀察 CPU、記憶體
  • 調整配置
  • 根據實際負載優化

Q4: Sync、Gevent、Gthread 各自最大的問題是什麼?

完整答案:

Sync Worker:

  • 最大問題:I/O 等待浪費
  • 場景:呼叫外部 API 需要 2 秒,Worker 就閒置 2 秒
  • 影響:並發能力低,資源利用率差
  • 解決:用 Gevent 或 Gthread

Gevent Worker:

  • 最大問題:CPU 密集型任務無效
  • 場景:複雜計算時無法切換協程,阻塞其他請求
  • 影響:一個慢請求影響所有請求
  • 解決:CPU 密集任務用 Sync 或移到 Celery

Gthread Worker:

  • 最大問題:GIL 限制真正並行
  • 場景:多線程 CPU 計算無法真正並行
  • 影響:CPU 密集型效能不如 Sync
  • 解決:純 CPU 密集用 Sync

總結:

  • 沒有完美的 Worker
  • 要根據應用特性選擇
  • 必要時可以混用(多個 Gunicorn 實例)

✅ 重點回顧

選擇原則

按任務類型:

  • CPU 密集 → Sync
  • I/O 密集(低並發)→ Gthread
  • I/O 密集(高並發)→ Gevent
  • 混合型 → Gthread

按並發需求:

  • < 50 → Sync
  • 50-500 → Gthread
  • 500 → Gevent

按應用場景:

  • CMS、後台 → Sync
  • 電商、企業應用 → Gthread
  • API 網關、聊天 → Gevent
  • 數據分析 → Sync

配置建議

Sync Worker:

workers = CPU_cores  # CPU 密集
workers = (2 × CPU_cores) + 1  # 混合型

Gevent Worker:

workers = (2 × CPU_cores) + 1
worker-connections = 1000-2000
# 記得 Monkey Patch!

Gthread Worker:

workers = (2 × CPU_cores) + 1
threads = 2-4  # 低並發
threads = 4-8  # 高並發

決策檢查清單

  • 分析了應用的 CPU vs I/O 比例
  • 評估了並發需求
  • 考慮了團隊技術棧
  • 檢查了第三方庫兼容性
  • 規劃了測試和監控方案
  • 準備了 Plan B(備用方案)

🎉 基礎篇完成!

恭喜你完成 Gunicorn Workers 基礎篇!

你現在已經掌握:

  • ✅ Gunicorn 的作用和重要性
  • ✅ Worker 的本質和工作原理
  • ✅ Sync、Gevent、Gthread 的特性
  • ✅ 如何根據場景選擇 Worker
  • ✅ 面試高頻問題的標準答案

📚 接下來的學習路徑

如果你在做新專案(Django 3.0+):

👉 強烈推薦:01-8. 現代方案:Gunicorn + Uvicorn Workers 🆕 了解如何使用現代 ASGI 方案部署 Django 專案

如果你要面試:

👉 直接跳到:05-1. 面試常見問題(基礎)

如果你在維護舊專案(WSGI):

👉 繼續學習:02-1. Workers 數量計算

如果你要深入:

👉 學習進階:03-1. 案例:I/O 密集型應用


🤓 最終測驗

測試你是否真正掌握了!

情境 1

一個社交媒體 API,需要呼叫 3 個外部服務獲取數據,預計並發 300 個,你會選什麼?

答案:Gthread Worker

理由:

  • I/O 密集(外部服務呼叫)
  • 並發 300(Gthread 範圍:50-500)
  • 配置:9 workers × 4 threads = 36 並發(可能需要調整到 10 workers × 4 threads)

情境 2

一個數據分析平台,用戶上傳 CSV 進行複雜統計,同時用戶不多(< 30),你會選什麼?

答案:Sync Worker

理由:

  • CPU 密集(數據分析、統計計算)
  • 低並發(< 30)
  • 配置:workers = CPU_cores(例如 4 核就 4 workers)

情境 3

一個爬蟲服務,需要同時抓取 1000 個網頁,你會選什麼?

答案:Gevent Worker

理由:

  • I/O 密集(網絡請求)
  • 超高並發(1000 個)
  • 配置:4 workers × 2000 connections = 8000 並發
  • 必須加 Monkey Patch

情境 4

一個電商網站,有購物車、結帳、推薦系統,並發約 150,你會選什麼?

答案:Gthread Worker

理由:

  • 混合型(資料庫 + 計算 + 可能的外部服務)
  • 中等並發(150)
  • 配置:9 workers × 4 threads = 36 並發(可能需要調整到 12 workers × 4 threads)

上一篇: 01-6. Gthread Worker 詳解 下一篇: 01-8. 現代方案:Gunicorn + Uvicorn Workers 🆕 或 05-1. 面試常見問題(基礎)


最後更新:2025-10-30

0%