go 语言等待组 sync.WaitGroup

sync.WaitGroup

Go 语言中除了可以等待组进行多个任务的同步,等待组可以保证在并发环境中完成指定数量的任务, 在 sync.WaitGroup(等待组)类型中,每个 sync.WaitGroup 值在内部维护着一个计数,此计数的初始默认值为零。

等待组的方法

方法名	功能
(wg * WaitGroup) Add(delta int)	等待组的计数器 +1
(wg * WaitGroup) Done()	等待组的计数器 -1
(wg * WaitGroup) Wait()	当等待组计数器不等于 0 时阻塞直到变 0。

对于一个可寻址的 sync.WaitGroup 值 wg:

我们可以使用方法调用 wg.Add(delta) 来改变值 wg 维护的计数。

方法调用 wg.Done() 和 wg.Add(-1) 是完全等价的。

如果一个 wg.Add(delta) 或者 wg.Done() 调用将 wg 维护的计数更改成一个负数,一个恐慌将产生。

当一个协程调用了 wg.Wait() 时,如果此时 wg 维护的计数为零,则此 wg.Wait() 此操作为一个空操作(noop);

否则(计数为一个正整数),此协程将进入阻塞状态。当以后其它某个协程将此计数更改至 0 时(一般通过调用 wg.Done()),此协程将重新进入运行状态(即 wg.Wait() 将返回)。

等待组内部拥有一个计数器,计数器的值可以通过方法调用实现计数器的增加和减少。当我们添加了 N 个并发任务进行工作时,就将等待组的计数器值增加 N。每个任务完成时,这个值减 1。同时,在另外一个 goroutine 中等待这个等待组的计数器值为 0 时,表示所有任务已经完成。

利用等待组保证协程执行完毕的例子

package main

import (
	"sync"
	"time"
)

var wg sync.WaitGroup

func say() {
	for i := 1; i <= 10; i++ {
		println("say ... ", i)
		time.Sleep(time.Millisecond * 100)
	}
	wg.Done()
}

func sayHi() {
	for i := 1; i <= 10; i++ {
		println("say hi ... ", i)
		time.Sleep(time.Millisecond * 100)
	}
	wg.Done()
}

func main() {
	// 开启协程
	wg.Add(2)
	go say()
	go sayHi()
	// 主线程与协程同时运行,当主进程运行完毕后协程也会被关闭
	// 所以主线程应该等待协程运行完成后再退出
	wg.Wait()
	println("main end")
}