一、《go 并发编程》goroutine

198 阅读1分钟

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 会进行一系列的初始化工作,涉及的工作内容大致如下:

  1. 创建一个特殊的defer语句,用于在主goroutine退出时做必要的善后处理。因为主goroutine也可能非正常的结束
  2. 启动专用于在后台清扫内存垃圾的 goroutine,并设置 GC 可用的标识
  3. 执行 mian 包中的 init 函数
  4. 执行 main 函数
  5. 执行完 main 函数后,它还会检查主 goroutine 是否引发了运行时恐慌,并进行必要的处理
  6. 最后主 goroutine 会结束自己以及当前进程的运行。