主goroutine是主线程的意思?
回答:不是
严格说,Go 里没有"主线程"这个概念;
"主goroutine"和"主线程"是两个层次的东西。
主 goroutine 和 主线程 的区别
| 概念 | 本质 | 在 Go 中的情况 |
|---|---|---|
| 主 goroutine | 执行 main.main() 的那个协程 | 确实存在,每个 Go 程序都有 |
| 主线程 | 进程启动时的那个 OS 线程 | 不算 Go 的概念,Go 程序启动时也会有 OS 线程,但不是"一个固定的主线程" |
主 goroutine 运行在操作系统创建的OS线程上
程序启动时,Go 运行时会创建一个 OS 线程(M)初始 OS 线程其实由操作系统创建
然后在它上面运行主goroutine(G),
主goroutine 再调用main() :
OS 线程(M) ← 由操作系统调度到 CPU 核心
└── 主goroutine(G) ← 执行 main.main()
所以:
- 主goroutine 运行在某个 OS 线程上 ,但它(主goroutine)本身不是线程
- 主goroutine 可以被换到别的 OS 线程上继续执行(Go 运行时调度决定的)
- 说"主线程"只是通俗说法,不严谨的叫法,go中压根没有主线程这个概念。
如果你非要说主线程;可以理解为:"主 goroutine"
特别说明:
1,初始 OS 线程其实由操作系统创建
2,主 goroutine 不固定绑定在这个线程上
更加准确的说明
程序启动时,操作系统先创建进程及其初始 OS 线程(M)
Go 运行时在该线程上初始化,并创建主 goroutine(G)
由主goroutine 再调用main()
主goroutine运行在这个 OS 线程上,但可能被调度器迁移到其他 M中去;
主goroutine 运行在某个 OS 线程上 ,但它(主goroutine)本身不是线程
整句话的意思是:
主 goroutine 只是"跑在"某个 OS 线程上面的一个执行单元 ,
但这个执行单元自己并不是一个线程。
OS 线程(M) ← 由操作系统调度到 CPU 核心
└── 主goroutine(G) ← 执行 main.main()
打个比方
OS 线程 = 铁轨上的火车(操作系统能调度的实体)
goroutine = 火车上拉的一节货物(Go 运行时调度的逻辑单元)
货物(goroutine) 搭乘 火车(OS 线程)才能前进
但货物本身不是火车 ------ 它可以从这列火车卸下来,
换到另一列火车上继续运输(goroutine 可以被调度到不同的 OS 线程上)
也就是说:主 goroutine ≠ 那个 OS 线程,只是暂时"跑在它上面"
有可能被调度器迁移到其他M(OS 线程)中去
goroutine 是逻辑执行流,线程是物理调度实体,二者不是同一个东西。
一个能感受到区别的细节
在 Java 里,主线程结束 = 进程结束;
在 Go 里, 主 goroutine 返回 时,程序会直接退出,
其他还在跑的 goroutine 会被强行终止 :
func main() {
go func() {
for {
fmt.Println("子协程还在跑")
time.Sleep(time.Second)
}
}()
// main 一旦返回,整个程序退出,上面这个 goroutine 也来不及继续
}
结论
"主goroutine" ≈ 运行main 函数的那个协程, 不是主线程 。
它是轻量级协程,只是恰好跑在某个 OS 线程上。
主 goroutine是什么?
主goroutine 是 Go 运行时创建、用来执行这个函数的那条执行流。
func main() { ... } 是 函数 (入口函数)
两者是"执行者"和"被执行的代码"的关系,不是同一个东西:
主 goroutine(执行者)
└── 被执行 func main() 里的代码
主 goroutine 的特点
主 goroutine 本身 没有特殊能力 ,
和其他 goroutine 一样是轻量级协程,
唯一特殊的是: 它一返回,程序就结束
func main()可以启动其他goroutine一起并行或者并发运行
func main() 里可以用go 启动其他 goroutine,
它们和主 goroutine 并行/并发运行