Sync包

Posted by Liao on 2022-06-22

sync包提供线程同步原语的方法

一、WaitGroup

1.1 Go语言标准库提供了WaitGroup原语,可以用来等待一批Goroutine结束,或者说让主协程等待子协程结束再操作。

1.2 使用例子

主协程是main,如果不加WaitGroup,则运行完就会先退出,没法打印字符串。

加上WaitGroup,让主协程等待5个子协程都执行完毕后,主协程再继续执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"sync"
)

func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1) //添加请求goroutine的数量,add(n),counter+=n s
go func() {
//每执行完一个goroutine,counter -= 1。
//当计数器counter为0时通过信号量调用runtime_Semrelease唤醒waiter线程
defer wg.Done()
fmt.Println("hello")
}()
}
wg.Wait() //waiter++,通过信号量runtime_Semacquire(semap)阻塞当前goroutine
}

二、map

三、mutex

1
2
3
4
type Mutex struct {
state int32 //存储互斥锁的状态,state = 0即是未加锁
sema uint32 //信号量,主要用作等待队列
}

四、RWMutex

适用于读多于写的场景

1
2
3
4
5
6
7
type RWMutex struct {
w Mutex // held if there are pending writers 复用互斥锁
writerSem uint32 // semaphore for writers to wait for completing readers 写操作的阻塞和唤醒的信号量
readerSem uint32 // semaphore for readers to wait for completing writers 读操作的阻塞和唤醒的信号量
readerCount int32 // number of pending readers 正在执行读的goroutine数量
readerWait int32 // number of departing readers 被阻塞的准备读的goroutine(groutine获取了写锁,若后面有goroutine要读,那么这些goroutine会被阻塞)
}

五、Once

场景:实现单例模式

1
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
package main

import (
"fmt"
"sync"
)

type mydb struct {
name string
}

//需要声明在外面
var (
once sync.Once
instance *mydb
)

func (s *mydb) getinstance() *mydb {
once.Do(func() {
instance = &mydb{ // 实例化,返回mydb结构体的引用
name: "mysql",
}
})
return instance
}

func main() {
var s *mydb
ans1 := s.getinstance()
ans2 := s.getinstance()

fmt.Printf("s1: %p\n", ans1) //s1: 0x1400008e210
fmt.Printf("s2: %p\n", ans2) //s2: 0x1400008e210
}

六、pool