Go Runtime(六):Netpoll与Syscall
本文源码基线为 Go 1.26.2、Linux/amd64。尤其注意:Go 1.26.2 已不再使用历史上的 _Psyscall 状态;旧文章基于 _Psyscall 描述的状态机不能直接套用到当前源码。 网络等待和阻塞系统调用都会让当前 goroutine 暂时无法继续,但 runtime 的处理方式不同: TEXT非阻塞 fd + netpoll G 等在 runtime 中,M/P 可以继续调度 阻塞 syscall M 等在内核中,runtime 设法把 P 交给其他 M 理解这一区别,就能解释 Go 为什么能用同步风格编写高并发网络服务,以及为什么某些 syscall 仍会增加线程数量。 从net.Conn.Read到runtime 以 Unix 上 TCP 读取为例,调用链可简化为: TEXTnet.(*TCPConn).Read -> netFD.Read -> internal/poll.(*FD).Read -> syscall.Read -> 数据就绪:直接返回 -> EAGAIN:pollDesc.waitRead -> runtime_pollWait -> runtime.netpollblock -> gopark socket 被设置为非阻塞。第一次 read 仍然是真实系统调用;只有内核返回 EAGAIN/EWOULDBLOCK 时,当前 G 才进入 netpoll 等待。 ...