为什么Go执行外部命令时会创建额外线程?是否可以避免?
额外线程的作用
你观测到的编号1494~1497的带-{s}前缀的线程,是Go运行时(runtime)原生创建的内核级工作线程(调度模型中的M),和os/exec包的外部命令执行逻辑没有直接绑定,这些线程的核心作用包括:
- 承担goroutine的调度、上下文切换工作
- 处理GC、信号监听、系统调用封装等runtime后台任务
- 当你调用
cmd.Run()执行外部命令时,底层会触发阻塞式的系统调用,Go runtime为了不阻塞其余goroutine的调度,会把当前绑定的逻辑处理器(P)转移给其他空闲内核线程,没有可用空闲线程时就会新建线程,这就是执行外部命令时线程数上涨的直接原因。
是否可以避免创建这类线程
无法完全避免Go runtime创建内核线程,这是Go M:N调度模型的底层设计决定的,但可以通过参数调整限制线程数量,减少不必要的线程创建:
- 调整
GOMAXPROCS环境变量,限制逻辑处理器(P)的数量,GOMAXPROCS的数值直接决定了同时可运行用户goroutine的内核线程上限,比如执行GOMAXPROCS=1 ./s启动程序,你的测试场景下只会保留1~2个内核线程,不会出现4个额外线程的情况。 - 如果你有极低线程数的硬性要求,可以限制程序中所有阻塞系统调用的使用场景,避免runtime因调度需要创建新线程,极端场景下可以把线程总数控制在个位数以内。
内容的提问来源于stack exchange,提问作者renton
相关产品推荐
相关产品推荐

