What is the netpoller and how does it make network I/O look blocking yet scale?
Question 158HardGo 1.22 to 1.25
The netpoller is a runtime layer over the OS readiness APIs: epoll on Linux, kqueue on BSD/macOS, IOCP on Windows. Sockets are opened in non-blocking mode. When conn.Read gets EAGAIN, the goroutine parks on the fd's pollDesc (gopark). Neither the thread nor the P is blocked, and the P runs other goroutines.
The runtime calls netpoll in three places:
- From
findRunnable, when a P has no work. - From
sysmon, if nobody has polled for about 10 ms. - From the scheduler, as a blocking wait when every P is idle.
Goroutines whose fds are ready become runnable again. Deadlines (SetReadDeadline) are integrated with runtime timers.
This gives you a simple blocking, goroutine-per-connection programming model with event-loop-level scalability. You can serve 100k idle connections with only a handful of threads.
Gotchas:
- Regular disk files do not use the netpoller on Linux, so they block a thread.
- Each connection still costs a goroutine stack plus buffers, often 4–10 KB or more, which matters for millions of connections.
- DNS lookups through cgo also block threads.
More on Goroutines & the Scheduler
- Q156Should you set GOMAXPROCS higher than the number of CPUs for I/O-bound workloads?
- Q157What happens to the scheduler when a goroutine makes a blocking syscall?
- Q159What is sysmon and what does it do?
- Q160What does runtime.Gosched do and when (if ever) should you use it?
- Q161What does runtime.LockOSThread do and when is it needed?
- Q162What is a goroutine leak? Give common causes.