goroutine
来一段伪代码
package main
import (
"fmt"
)
func main() {
// 运行子 goroutine
go printNum()
// 主 goroutine 执行
for i := 1; i < 10; i++ {
fmt.Println("\tA",i)
}
}
// 子 goroutine 执行
func printNum() {
for i := 1; i < 10; i++ {
fmt.Println("B",i)
}
}
执行结果
# 分析
# 1、封装main函数的 goroutine 称为主 goroutine,在main下执行的 goroutine 为子 goroutine
# 2、程序在并发运行时,主、子的 goroutine 会交替切换执行
# 3、从执行结果来看,当主 goroutine 执行完后,子 goroutine 也会跟着结束,不会去管子 goroutine 有没有执行完
A 1
A 2
A 3
A 4
A 5
A 6
A 7
A 8
A 9
main over .....
B 1
B 2
B 3
B 4
怎么去解决这个问题呢,在没有学习channel之前,可以在主 goroutine 执行时先睡眠2s,然后 printNum() 就会有足够的时间在 main goroutine 终止之前执行完
package main
import (
"fmt"
)
func main() {
// 运行子 goroutine
go printNum()
// 主 goroutine 执行
for i := 1; i < 10; i++ {
fmt.Println("\tA",i)
}
}
// 子 goroutine 执行
func printNum() {
for i := 1; i < 10; i++ {
fmt.Println("B",i)
}
}
执行的结果
B 1
B 2
B 3
B 4
B 5
B 6
B 7
B 8
B 9
A 1
A 2
A 3
A 4
A 5
A 6
A 7
A 8
A 9
main over .....
主 goroutine 会进行一系列的初始化工作,涉及的工作内容大致如下:
- 创建一个特殊的defer语句,用于在主goroutine退出时做必要的善后处理。因为主goroutine也可能非正常的结束
- 启动专用于在后台清扫内存垃圾的 goroutine,并设置 GC 可用的标识
- 执行 mian 包中的 init 函数
- 执行 main 函数
- 执行完 main 函数后,它还会检查主 goroutine 是否引发了运行时恐慌,并进行必要的处理
- 最后主 goroutine 会结束自己以及当前进程的运行。