sync包WaitGroup
# 一、sync
包 ---WaitGroup
- https://golang.google.cn/pkg/sync/
官方文件sync
的介绍
Package sync provides basic synchronization primitives such as mutual exclusion locks. Other than the Once and WaitGroup types, most are intended for use by low-level library routines. Higher-level synchronization is better done via channels and communication
sync
是synchronization
同步这个词的缩写,所以也会叫做同步包.这里提供了基本同步的操作,比如互斥锁等等.这里除了Once
和WaitGroup
类型之外,大多数类型都是供低级库例教程使用的.更高级别同步最好通过channel
通道和communication
通信来完成
# 一、WaitGoup
WaitGroup
,同步等待组.
在类型上,它是一个结构体.一个WaitGroup
的用途是等待一个goroutine
的集合执行完成.主要goroutine
调用了Add()
方法来设置要等待的goroutine
的数量.然后,每个goroutine
都会执行并且执行完成后调用Done()
这个方法.与此同时,可以使用Wait()
方法来阻塞,知道所有goroutine
多执行完成.
# 二、Add()
方法
Add
这个方法,用来设置到WaitGroup
的计数器的值.可以理解为每个waitgroup
中都有一个计数器用来表示这个同步等待组中要执行的goroutine
的数量.
如果计数器的数值变为0
,那么就表示等待时被阻塞的goroutine
都被释放,如果计数器的数值为负数,那么就会引发恐慌,程序就报错了.
func (wg *WaitGroup) Add(delta int) {
statep, semap := wg.state()
if race.Enabled {
_ = *statep // trigger nil deref early
if delta < 0 {
// Synchronize decrements with Wait.
race.ReleaseMerge(unsafe.Pointer(wg))
}
race.Disable()
defer race.Enable()
}
state := atomic.AddUint64(statep, uint64(delta)<<32)
v := int32(state >> 32)
w := uint32(state)
if race.Enabled && delta > 0 && v == int32(delta) {
// The first increment must be synchronized with Wait.
// Need to model this as a read, because there can be
// several concurrent wg.counter transitions from 0.
race.Read(unsafe.Pointer(semap))
}
if v < 0 {
panic("sync: negative WaitGroup counter")
}
if w != 0 && delta > 0 && v == int32(delta) {
panic("sync: WaitGroup misuse: Add called concurrently with Wait")
}
if v > 0 || w == 0 {
return
}
// This goroutine has set counter to 0 when waiters > 0.
// Now there can't be concurrent mutations of state:
// - Adds must not happen concurrently with Wait,
// - Wait does not increment waiters if it sees counter == 0.
// Still do a cheap sanity check to detect WaitGroup misuse.
if *statep != state {
panic("sync: WaitGroup misuse: Add called concurrently with Wait")
}
// Reset waiters count to 0.
*statep = 0
for ; w != 0; w-- {
runtime_Semrelease(semap, false, 0)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 三、Done()
方法
Done()
方法,就是当WaitGroup
同步等待中的某个goroutine
执行完毕后,设置这个WaitGroup
的counter
数值减1.
其实Done()
底层代码就是调用了Add()
方法:
// Done decrements the WaitGroup counter by one.
func (wg *WaitGroup) Done() {
wg.Add(-1)
}
2
3
4
# 四、Wait()
方法
Wait()
方法,表示让当前的goroutine
等待,进入阻塞状态.一直到WaitGroup
的计数器为零.才能解除阻塞,这个goroutine
才能继续执行.
# 五、示例代码
创建并启动两个goroutine
,来打印数字和字母,并在main goroutine
中,将这两个子goroutine
加入到一个WaitGroup
中,同时让main goroutine
进入Wait()
,让两个子goroutine
先执行.当每个goroutine
执行完毕之后,调用Done()
方法,设置WaitGroup
的counter
减1。当两条子goroutine
都执行完毕后,WaitGroup
中的counter
的数值为零,解除main goroutine
的阻塞.
示例代码
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup // 创建同步等待组对象
func main() {
/*
WaitGroup:同步等待组
可以使用Add(),设置等待组中要 执行的子goroutine的数量,
在main 函数中,使用wait(),让主程序处于等待状态。直到等待组中子程序执行完毕。解除阻塞
子gorotuine对应的函数中。wg.Done(),用于让等待组中的子程序的数量减1
*/
//设置等待组中,要执行的goroutine的数量
wg.Add(2)
go fun1()
go fun2()
fmt.Println("main进入阻塞状态。。。等待wg中的子goroutine结束。。")
wg.Wait() //表示main goroutine进入等待,意味着阻塞
fmt.Println("main,解除阻塞。。")
}
func fun1() {
for i:=1;i<=10;i++{
fmt.Println("fun1.。。i:",i)
}
wg.Done() //给wg等待中的执行的goroutine数量减1.同Add(-1)
}
func fun2() {
defer wg.Done()
for j:=1;j<=10;j++{
fmt.Println("\tfun2..j,",j)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- 01
- AWS NAT-NetWork-Firwalld配置(一)04-09
- 02
- AWS NAT-NetWork-Firwalld配置(二)04-09
- 03
- kubernetes部署minio对象存储01-18