Skip to content
All writing Part 03 of 11 · From 19 Goroutines to Exit 137
Engineering · 3 min read

GMP Scheduler and Netpoller: I/O Waiting Costs Zero CPU

One OS thread waits on thousands of sockets; each waiter is a ~2KB goroutine. How the GMP scheduler parks and wakes I/O-bound goroutines.

One OS thread waits on thousands of sockets; each waiter is just a ~2KB goroutine.

The GMP Model

GOMAXPROCS = 1 P₀ (logical processor) M (OS thread) G₁ running ▶ netpoller (epoll): G₅ ⏸ G₆ ⏸ ... G₁₉ ⏸ waiting on socket 0 CPU / 0 P / 0 M all "in-flight"
  • G = goroutine (~2KB), M = OS thread (~1MB), P = logical processor (count = GOMAXPROCS). A G must bind to a P bound to an M to execute. At most GOMAXPROCS goroutines run Go code in parallel at any instant.
  • Park: goroutine reads a socket and gets EAGAIN → runtime calls gopark, sets G to _Gwaiting, registers the fd with epoll, and frees the P/M. A parked G holds 0 CPU.
  • Wake: socket becomes ready → epoll returns the fd → runtime maps fd back to G → goready marks G as _Grunnable → P/M resumes execution right after Read().
G: conn.Read(browser) socket empty → EAGAIN PARK gopark(G) → _Gwaiting fd registered with epoll, 0 CPU P/M freed → run other goroutines Browser responds → kernel marks fd READY WAKE epoll_wait → ready fd goready(G) → _Grunnable P/M resumes G right after Read()

Role in This OOM

Each /capture goroutine in the screenshot service spent ~99% of its time parked on the browser’s websocket. With GOMAXPROCS=1, 19 goroutines were simultaneously in-flight (each with an open browser tab), but only 1 was “running”. The 19 tabs and their memory all existed at once (GOMAXPROCS Caps Parallelism, Not Concurrency).

I/O-parked doesn’t mean non-existent. The goroutine holds zero CPU, but the browser tab it opened holds real memory.

References:

Related: see GOMAXPROCS Caps Parallelism, Not Concurrency for why cpu:1 wasn’t enough, Load Shedding with TryAcquire for the semaphore fix, or go back to the series overview.

Tags #go #concurrency #reliability
// connect

Be brave | Be wise | Be grateful

21 BreakinCode

// elsewhere
LinkedInMedium (lang: en)Life RecordYoutube
wh:~$William Hung· © 2026 Taipei · GMT+8 · Available for collaboration