Yoru Karu Studio
程式設計學習筆記 | 生活心得程式設計學習筆記 | 生活心得
🎯 本章重點 通過實際的配置文件範例,學習如何為不同場景配置 Gunicorn。
⭐ 2025 年新專案建議 結論:Django 3.0+ 新專案,請直接使用 ASGI (範例3)
為什麼?
✅ 性能更好(比 WSGI 快 10-35 倍) ✅ 向後兼容同步代碼(不需要改現有代碼) ✅ 支援 WebSocket、SSE 等現代功能 ✅ Django 官方推薦的未來方向 ✅ 一個 worker 可處理數千並發 什麼時候才用 WSGI (範例2)?
⚠️ 只有 Django 2.x 遺留系統無法升級時 ⚠️ 極少數第三方套件不支援 ASGI(非常罕見) 📊 Workers 數量計算說明 在配置文件中你會看到不同的 workers 計算方式,這裡先統一說明:
multiprocessing.cpu_count() 是什麼? import multiprocessing # 自動取得 CPU 核心數 workers = multiprocessing.cpu_count() # 例如: # - 4 核 CPU → workers = 4 # - 8 核 CPU → workers = 8 # - 16 核 CPU → workers = 16不同 Worker 類型的數量公式 Worker 類型 Workers 數量公式 原因 Sync (WSGI) CPU * 2 + 1 需要處理 I/O 等待,需要更多 workers Uvicorn (ASGI) CPU 異步處理,一個 worker 可處理數千並發 Gevent CPU * 2 + 1 協程模型,需要多個 workers 分散負載 Gthread CPU * 2 + 1 多線程,需要更多進程配合 範例對比 # 假設 4 核 CPU # 範例 2:Sync Worker (WSGI) workers = multiprocessing.
🎯 本章重點 學習如何為 I/O 密集型應用配置 Gunicorn,這是最常見的 Web 應用類型。
📊 什麼是 I/O 密集型應用? 定義 I/O 密集型應用:大部分時間在等待外部資源響應,而不是 CPU 計算。
一個請求的時間分配: 總時間:1000ms ├── CPU 計算:50ms (5%) ← 很少 └── I/O 等待:950ms (95%) ← 大部分時間 ├── 資料庫查詢:400ms ├── Redis 讀取:100ms ├── 外部 API 調用:350ms └── 文件讀寫:100ms典型特徵 # I/O 密集型應用的特徵 ✅ 大量外部調用: - 數據庫查詢(PostgreSQL、MySQL、MongoDB) - 緩存讀寫(Redis、Memcached) - 外部 API 調用(支付、簡訊、天氣 API) - 文件操作(讀寫、上傳、下載) - 消息隊列(RabbitMQ、Kafka) ✅ 響應時間特徵: - 平均響應時間:100-500ms - P95 響應時間:500ms-2s - 時間主要花在等待而非計算 ❌ 不是 I/O 密集型: - 影像處理(resize、濾鏡) - 視頻轉碼 - 大量數學計算 - 機器學習推理 - 加密解密(大量數據) 🏗️ 典型場景 場景 1:API 網關 # myapp/views.
🎯 本章重點 學習如何為 CPU 密集型應用配置 Gunicorn,以及為什麼這類應用需要不同的策略。
📊 什麼是 CPU 密集型應用? 定義 CPU 密集型應用:大部分時間在進行 CPU 計算,而不是等待 I/O。
一個請求的時間分配: 總時間:1000ms ├── CPU 計算:950ms (95%) ← 大部分時間 └── I/O 等待:50ms (5%) ← 很少 ├── 讀取文件:30ms └── 寫入結果:20ms與 I/O 密集型的對比:
I/O 密集型: 時間軸 ────────────────────────────────── ↓ CPU ↓等待...↓CPU ↓等待...↓CPU [5%] [30%] [5%] [30%] [5%] CPU 密集型: 時間軸 ────────────────────────────────── ↓ 持續 CPU 計算........................↓ [────────────── 95% ─────────────]典型特徵 # CPU 密集型應用的特徵 ✅ 大量計算操作: - 影像處理(縮圖、濾鏡、轉換格式) - 視頻轉碼(H.264、H.265 編碼) - 數據分析(統計、機器學習推理) - 加密解密(AES、RSA 大量數據) - 複雜算法(排序、搜索、圖算法) - 科學計算(數值模擬、矩陣運算) ✅ CPU 使用率特徵: - CPU 使用率:80-100% - I/O wait:< 10% - 響應時間取決於 CPU 速度 ❌ 不是 CPU 密集型: - 簡單的 CRUD 操作 - API 調用轉發 - 查詢資料庫後返回 - 文件上傳下載 🏗️ 典型場景 場景 1:圖片處理服務 # myapp/views.
🎯 本章重點 學習如何為既有 I/O 操作又有 CPU 計算的混合型應用選擇最佳配置。
📊 什麼是混合型應用? 定義 混合型應用:既有大量 I/O 等待,又有相當比例的 CPU 計算。
一個請求的時間分配(混合型): 總時間:1000ms ├── I/O 等待:600ms (60%) ← 主要部分 │ ├── 資料庫查詢:300ms │ ├── Redis 讀取:100ms │ └── API 調用:200ms │ └── CPU 計算:400ms (40%) ← 不可忽視 ├── 數據處理:150ms ├── JSON 序列化:100ms ├── 業務邏輯計算:100ms └── 模板渲染:50ms與純 I/O、純 CPU 的對比:
純 I/O 密集型: ├── I/O 等待:95% └── CPU 計算:5% → 使用 ASGI (Uvicorn Worker) 純 CPU 密集型: ├── CPU 計算:95% └── I/O 等待:5% → 使用 Sync Worker 混合型: ├── I/O 等待:50-70% └── CPU 計算:30-50% → 需要權衡選擇!典型特徵 # 混合型應用的特徵 ✅ 既有 I/O 操作: - 查詢資料庫(中等複雜度) - 調用外部 API(少量) - 讀寫 Cache ✅ 也有 CPU 計算: - 數據處理和轉換 - 複雜業務邏輯 - JSON 序列化(大量數據) - 模板渲染 - 輕量級圖片處理 ✅ 時間分配特徵: - I/O 等待:50-70% - CPU 計算:30-50% - 兩者都不可忽視 ❌ 不是混合型: - 只查資料庫返回 → 純 I/O - 只做複雜計算 → 純 CPU 🏗️ 典型場景 場景 1:電商商品列表頁 # myapp/views.
🎯 本章重點 學習如何將 Django + Gunicorn 應用部署到生產環境,包含完整的配置、監控和維護。
🏗️ 生產環境架構 標準架構圖 Internet ↓ ┌─────────────────────────────────────────────┐ │ Cloudflare / CDN │ │ • DDoS 防護 │ │ • SSL/TLS │ │ • 靜態資源緩存 │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Nginx (反向代理 + 負載均衡) │ │ • 端口:80 (HTTP) / 443 (HTTPS) │ │ • 功能: │ │ - 反向代理到 Gunicorn │ │ - 靜態文件服務 │ │ - SSL 終止 │ │ - Gzip 壓縮 │ │ - 請求限流 │ │ - 健康檢查 │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Gunicorn (WSGI/ASGI Server) │ │ • 端口:8000 (內部) │ │ • 配置: │ │ - workers = CPU 核心數 │ │ - worker_class = "uvicorn.
Tree(樹)資料結構完整教學 什麼是樹? 樹(Tree)是一種非線性的階層式資料結構,由節點(nodes)和邊(edges)組成。樹模擬了現實世界中的階層關係,如組織架構、檔案系統、決策過程等。
樹的基本概念 A <- 根節點 (Root) / | \ B C D <- 內部節點 (Internal Nodes) /| \ E F G <- 葉節點 (Leaf Nodes)重要術語 節點(Node):樹的基本單位,包含資料和指向其他節點的連結 根(Root):樹的最頂層節點,沒有父節點 父節點(Parent):有子節點的節點 子節點(Child):從屬於另一個節點的節點 葉節點(Leaf):沒有子節點的節點 兄弟節點(Siblings):有相同父節點的節點 深度(Depth):從根到該節點的邊數 高度(Height):從該節點到最深葉節點的邊數 子樹(Subtree):節點及其所有後代組成的樹 二元樹(Binary Tree) 二元樹是每個節點最多有兩個子節點的樹結構。
基本實作 class TreeNode: """二元樹節點""" def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def __repr__(self): return f"TreeNode({self.val})" class BinaryTree: """二元樹基本實作""" def __init__(self): self.root = None def __repr__(self): if not self.