四、《go 并发编程》sync包WaitGroup

113 阅读2分钟
理解WaitGroup

WaitGroup,同步等待组。 在类型上,它是一个结构体。一个WaitGroup的用途是等待一个goroutine的集合执行完成。主goroutine调用了Add()方法来设置要等待的goroutine的数量。然后,每个goroutine都会执行并且执行完成后调用Done()这个方法。与此同时,可以使用Wait()方法来阻塞,直到所有的goroutine都执行完成。

开看看几个重要的方法
package main

import "sync"

var g sync.WaitGroup

func main() {
// Add这个方法,用来设置到WaitGroup的计数器的值。我们可以理解为每个waitgroup中都有一个计数器
// 用来表示这个同步等待组中要执行的goroutin的数量。

// 如果计数器的数值变为0,那么就表示等待时被阻塞的goroutine都被释放,如果计数器的数值为负数,那么就会引发恐慌,程序就报错了。
	g.Add(1)
  // 就是当WaitGroup同步等待组中的某个goroutine执行完毕后,设置这个WaitGroup的counter数值减1
	g.Done()
  // 表示让当前的goroutine等待,进入阻塞状态。一直到WaitGroup的计数器为零。才能解除阻塞,这个goroutine才能继续执行
	g.Wait()
}

// Done() 源码
func (wg *WaitGroup) Done() {
  // 就是操作 Add(-1)
	wg.Add(-1)
}
上代码
package main

import (
	"fmt"
	"sync"
)

var g sync.WaitGroup

func main() {
	// 定义等待组,要执行的 goroutine 为 2
	g.Add(2)
	// 执行 goroutine
	go fun1()
	go fun2()
	// main 进入阻塞状态,等待 g 当中的 goroutine 执行完
	fmt.Println("我是主 goroutine ,我刷点存在感。。。")
	// 进入等待
	g.Wait()
	// 解除阻塞
	fmt.Println("我还是主 goroutine,我再来点存在感,拜拜。。。")
}

func fun1()  {
	// 执行
	fmt.Println("我是fun1,我在工作。。。")
	// 等待组 -1
	g.Done()
	// 结束执行
	fmt.Println("我是fun1。。。我完事了")
}

func fun2()  {
	// 执行
	fmt.Println("我是fun2,我在工作。。")
	// 等待组 -1
	g.Done()
	// 结束执行
	fmt.Println("我是fun2。。。我完事了")
}
执行结果
我是fun1,我在工作。。。
我是fun1。。。我完事了
我是主 goroutine ,我刷点存在感。。。
我是fun2,我在工作。。
我是fun2。。。我完事了
我还是主 goroutine,我再来点存在感,拜拜。。。
分析

image-20200923190711805