并发¶
goroutine¶
Golang 并发通过 goroutine
实现,类似于线程,属于用户态的线程。
goroutine
开销非常小,所以一个程序开辟数千个都没问题。
Golang 在语言层面已经内置了调度和上下文切换的机制,会智能地将 goroutine
种的任务合理地分配给每个CPU。
当需要让某个任务并发的执行时,只要把这个任务包装成一个函数,开启一个 goroutine
去执行这个函数即可。
主 goroutine¶
main()
函数自己本身就处于 主 goroutine
。
主 goroutine
结束的时候,其他执行完毕的、未执行完毕的 子 goroutine
也会一并被结束。
主 goroutine
的任务:
- 设定每个
goroutine
所能申请的栈空间的最大尺寸。 在 32 位系统中最大尺寸为 250MB,64 位系统中最大尺寸为 1GB。如果某个goroutine
的占空间尺寸大于这个限制,则运行时系统会引发一个栈溢出(Stack Overflow)的panic
,随后这个程序也会终止。 - 执行初始化工作:
- 创建一个特殊的
defer
语句,用于主 goroutine
退出时做必要的善后处理。因为主 goroutine
也可能非正常结束。 - 启动专用于
GC(Garbage Clean)
的goroutine
,并设置 GC 可用的标识。 - 执行
main
包中的init()
函数。 - 执行
main()
函数。
- 创建一个特殊的
- 在
main()
函数结束后,检查主 goroutine
是否引发了运行时 panic,并进行必要的处理。 - 最后,结束自己及当前进程的运行。
使用¶
一个 goroutine
必对应一个函数,可以创建多个 goroutine
去执行相同的函数。
只需要在函数调用处加上 go
关键字修饰,即可为一个函数创建一个 goroutine
。
输出:
在单个 goroutine
的例子中,为了防止 主 goroutine
快于 子 goroutine
完成,导致 子 goroutine
来不及完成就退出程序,在 main()
中添加了一条 time.Sleep()
。虽然暂时可以解决这个问题,但是不优雅,也不科学。
Info
所以我们需要使用 sync.WaitGroup
来同步多个 goroutine
。
使用步骤:
- 声明一个
sync.WaitGroup
对象 - 添加一个计数器
- 调用
Wait()
等待 - 在
goroutine
中defer
修饰sync.WaitGroup
的Done()
方法
输出: