Sync包详解

Once

对象用来确保只执行一次的处理场景,注意这里的一次只是对于单个进程,且这个Once对象没有被复制的情况,在分布式的应用中,这个对象可能并不适用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func TestOnce(f *testing.T) {
var once sync.Once
onceBody := func() {
fmt.Println("Only once")
}
done := make(chan bool)
for i := 0; i < 10; i++ {
go func() {
once.Do(onceBody)
done <- true
}()
}
for i := 0; i < 10; i++ {
<-done
}
}

Pool

对象池,用来生成以及缓存对象,如果池子里没有对象,则会调用New方法创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func TestPool(f *testing.T) {
var pool = sync.Pool{
New: func() interface{} {
return bytes.NewBuffer([]byte("init:"))
},
}

buff := pool.Get().(*bytes.Buffer)
buff.Write([]byte("one"))
fmt.Println(buff.String())

pool.Put(bytes.NewBuffer([]byte("two")))
buff2 := pool.Get().(*bytes.Buffer)
fmt.Println(buff2.String())
}

打印结果

1
2
init:one
two

Map

Map对象和 map[interface{}]interface{} 类似,只不过Map是线程安全的,并且提供了一些增删改查的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func TestMap(f *testing.T) {

var mp sync.Map

mp.Store("name", "jack")
mp.Store("age", "20")

v, ok := mp.Load("name")
if ok {
fmt.Println(v)
}

mp.Range(func(key, value interface{}) bool {
fmt.Println(key, value)
return true
})
}

其中Range方法,用于遍历map,如果返回false,则终止遍历

Mutex

Mutex 互斥锁,用来保证同一时间不能有多个并发协程访问某一个资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

type Wallet struct {
Amount float64
lock sync.Mutex
}

func (w *Wallet) Increase() {
if w.lock.TryLock() {
w.Amount += 1
w.lock.Unlock()
}
}
func (w *Wallet) Decrease() {
if w.lock.TryLock() {
w.Amount -= 1
w.lock.Unlock()
}
}

RWMutex

RWMutex 读写锁,多个并发协程同时读取某一个资源,但只有一个并发协程能够更新资源

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
35
36
37
38
39
40
41
42
43

type Bank struct {
sync.RWMutex
balance map[string]float64
}

func (b *Bank) In(account string, value float64) {
b.Lock()
defer b.Unlock()

v, ok := b.balance[account]
if !ok {
b.balance[account] = 0.0
}

b.balance[account] += v
}

func (b *Bank) Out(account string, value float64) error {
b.Lock()
defer b.Unlock()

v, ok := b.balance[account]
if !ok || v < value {
return errors.New("account not enough balance")
}

b.balance[account] -= value
return nil
}

func (b *Bank) Query(account string) float64 {
b.RLock()
defer b.RUnlock()

v, ok := b.balance[account]
if !ok {
return 0.0
}

return v
}

WaitGroup

等待组,场景多用于等待多个任务都处理完成之后

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

type httpPkg struct{}

func (httpPkg) Get(url string) {}

var http httpPkg

func main() {
var wg sync.WaitGroup
var urls = []string{
"http://www.golang.org/",
"http://www.google.com/",
"http://www.example.com/",
}
for _, url := range urls {
// Increment the WaitGroup counter.
wg.Add(1)
// Launch a goroutine to fetch the URL.
go func(url string) {
// Decrement the counter when the goroutine completes.
defer wg.Done()
// Fetch the URL.
http.Get(url)
}(url)
}
// Wait for all HTTP fetches to complete.
wg.Wait()
}

Sync包详解
https://www.xinyublog.com/golang/sync/
作者
蚂蚁
发布于
2023年8月17日
许可协议