Go 线程膨胀问题

在 Go 中 GOMAXPROCS 变量可以限制并发运的 Goroutine 数量,也就是控制的 P 的数量。

但在实际运行中内核线程 M 往往会超过 GOMAXPROCS 的限制,也就是内核线程并不受GOMAXPROCS 变量的限制。

blocking syscall 导致线程增多

在发生系统调用是,如果运行时间过长,比如超过 10ms 就可能导致新的内核线程产生。监视器 sysmon 会定期轮询 runtime.allgs 中所有的逻辑处理器 P。如果 P 上的执行的系统调用时间阻塞较长,触发内核线程 M 与 P 分离。在后续调度中会通过 runtime.startm 来唤醒或产生新的 M 来与 P 绑定。这样如果在阻塞系统调用很多的场景就会导致产生很多的内核线程。

例如通过 read() 函数读文件操作,就是典型的阻塞调用。

go issue #14592

reference

https://colobu.com/2020/12/20/threads-in-go-runtime/

https://xargin.com/shrink-go-threads/

https://github.com/golang/go/issues/14592

http://xiaorui.cc/archives/5171