go 语言 主程序退出时会进行一些额外工作
主goroutine先执行完,子goroutine居然还可以运行
func main() {
ch := make(chan int)
log.Println("===========")
go func() {
log.Println("doing in sub goroutine")
// 主程序向通道发送数据,但此时由于 主 gor 行速度慢
// 程序还没有执行到 fmt.Println("x in ch is:", <-ch),
// 通道还没有接收数据,所以此时发生 阻塞
ch <- 1
log.Println("done in sub goroutine") // 竞争打印,顺序不定
}()
// 模拟执行速度慢
time.Sleep(1 * time.Second)
log.Println("doing in main goroutine")
// 1. 执行到这里时发生,由于子 gor 已经在等待向通道发送数据
// 所以此处的 从通道接收数据的 <-ch 立即执行
// 2. 子 gor 被唤酲, 立即向通道发送数据
// 3. <-ch 开始接收数据
// 当从通道中取出数据时,数据是通道中复制的,这需要花费一定的时间
fmt.Println("x in ch is:", <-ch) // 竞争打印,顺序不定
log.Println("done in main goroutine") // 竞争打印,顺序不定
}
output:这个比较奇怪,主 先执行完,子居然还可以运行
// 2021/03/04 16:26:35 doing in sub goroutine
// 2021/03/04 16:26:36 doing in main goroutine
// x in ch is: 1
// 2021/03/04 16:26:36 done in main goroutine (主 先执行完)
// 2021/03/04 16:26:36 done in sub goroutine (子居然还可以运行)
关于原因
Stack Overflow上的答案是 在主 gor 的最后一行代码
log.Println("done in main goroutine")
执行完成后,main 所在的 goroutine 还有一些在runtime
时需要完成一些扫尾工作,这些扫尾工作会花费非常少的时间,在这段时间里,子 gor 依然可以运行
所以可以执行
log.Println("done in sub goroutine")
这也说明了 此次 主 gor 运行的比较慢,给子gor 留下了运行完所有代码的时间
如果主 gor 运行的特别快,即使扫尾工作需要花费一定的时间,但整体速度依然比
子 gor 快,则
log.Println("done in sub goroutine")
不能被执行