Skip to content
所有文章 ‹ Part 04 of 11 · 從 19 個 goroutine 到 exit 137
工程 · 1 min read

GOMAXPROCS 限制平行,不限並發

cpu:1 不代表一次只跑一個。I/O-parked 的 goroutine 不受 GOMAXPROCS 約束。平行和並發是兩個不同的上限。

cpu:1 不代表一次只跑一個。I/O-parked 的 goroutine 不受 GOMAXPROCS 約束。

三個層次的「看起來有限但沒有」

GOMAXPROCS = 1 Running (P-bound) G₁ Parked (netpoller) G₂ G₃ ... G₁₉ ← 1 max ← no limit parallelism = 1 (caps Go code) concurrency = 19 (caps nothing)
  1. net/http 的隱含並發:每個請求自動開一個 goroutine,handler 裡再 go 出去。N 個請求 ≈ 2N 個 goroutine。沒有框架級上限。
  2. GOMAXPROCS 只限平行:它限制同時「執行 Go 程式碼」的 goroutine 數量。I/O-parked 的不算。Parked goroutine 佔 0 P/0 M(GMP 排程器)。
  3. runtime.NumCPU() 的陷阱:讀的是 node 的 core 數(如 64)。不是你的 cgroup quota(如 1)。pre-Go 1.25 需要 go.uber.org/automaxprocs 修正。但它只修 CPU,不修 memory OOM。

在這個 OOM 裡的角色

截圖服務用了 automaxprocs → GOMAXPROCS=1。看起來像「一次只跑一個」。實際上 19 個 /capture goroutine 同時 parked 在瀏覽器 websocket 上。每個開了一個分頁。GOMAXPROCS 給了一種不存在的安全感。

真正的上限要自己加:semaphore(TryAcquire load shedding)。

GOMAXPROCS 是 CPU 的上限。不是資源的上限。I/O-bound 的工作需要你自己加限制。

參考來源:

延伸閱讀: 參見GMP 排程器與 netpoller、用 TryAcquire 做 load shedding,或回到系列總覽。

↑↓ 移動 ↵ 開啟 esc 關閉