You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go Goroutine调度机制及运行原理相关技术问询

关于Goroutine工作方式的基础疑问

参考代码

package main

import (
    "fmt"
    "time"
)

type Country struct {
    Name       string
    Continent  string
    Population int32
}

func updatePopulation(c *Country, newBorns int32) {
    c.Population += newBorns
    fmt.Printf("New population of %v is %v\n", c.Name, c.Population)
}

func main() {
    totalStates := 50 // total number of sources, (US states)
    us := Country{"USA", "North America", 32000000}
    for i := 0; i <= totalStates; i++ {
        go updatePopulation(&us, int32(i))
    }
    time.Sleep(time.Second * 5)  // this is just so that we don't need channels
}

问题解答

1. 子Goroutine是否需要主Goroutine阻塞才会运行?

不是的。调用go关键字启动Goroutine时,Go运行时会立刻将该Goroutine加入调度队列,只要调度器有空闲的逻辑处理器(P),就会安排它执行。示例中的time.Sleep只是为了阻止主Goroutine提前退出——如果主Goroutine直接结束,整个程序会终止,所有未完成的子Goroutine都会被强制终止,和子Goroutine的启动时机无关。

2. 无阻塞Goroutine执行顺序混乱的原因?

首先需要纠正:Go从1.14版本开始默认启用抢占式调度,不再是单纯的协作式。即使Goroutine没有阻塞操作,调度器也会在Goroutine运行超过约10ms、或者遇到函数调用时进行抢占,切换到其他Goroutine执行。另外,当GOMAXPROCS值大于1时,多个Goroutine可以被调度到不同的OS线程上,在多CPU核心上真正并行执行,这会进一步导致执行顺序无规律——最终的执行顺序由Go运行时调度器和操作系统的线程调度共同决定,没有固定顺序。

3. Go Runtime的线程池是否针对每个程序实例?

是的。每个Go程序执行实例(进程)都会拥有独立的线程池(由OS线程M组成),这些线程用于绑定逻辑处理器(P),进而调度Goroutine。线程池的大小会动态调整:当有Goroutine因IO、系统调用等阻塞时,Runtime会创建新线程来保证其他Goroutine的调度;当阻塞解除后,多余的线程会被回收。不同程序实例的线程池相互独立,互不影响。

内容的提问来源于stack exchange,提问作者Ram Dittakavi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 22:30:57