Engineering · 1 min read
GOMAXPROCS 限制平行,不限並發
cpu:1 不代表一次只跑一個。I/O-parked 的 goroutine 不受 GOMAXPROCS 約束。平行和並發是兩個不同的上限。
cpu:1不代表一次只跑一個。I/O-parked 的 goroutine 不受 GOMAXPROCS 約束。
三個層次的「看起來有限但沒有」
net/http的隱含並發:每個請求自動開一個 goroutine,handler 裡再go出去,N 個請求 ≈ 2N 個 goroutine,沒有框架級上限。- GOMAXPROCS 只限平行:它限制同時「執行 Go 程式碼」的 goroutine 數量。I/O-parked 的不算。Parked goroutine 佔 0 P/0 M(GMP 排程器)。
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 的工作需要你自己加限制。
參考來源:
- https://pkg.go.dev/net/http#Server
- https://go.dev/blog/container-aware-gomaxprocs
- https://victoriametrics.com/blog/kubernetes-cpu-go-gomaxprocs/
- https://kanishk.io/posts/cpu-throttling-in-containerized-go-apps/
Related: 參見GMP 排程器與 netpoller、用 TryAcquire 做 load shedding,或回到系列總覽。