Golang为了能够充分利用多核CPU的性能,在调度系统中使用了多线程,也就是Goroutine是跑在多个线程中,当多个Goroutine访问同一个资源是会出现c/cpp/java中并发问题; Sync包就是来解决这些并发问题
1. Sync中锁
在sync包中有两种锁,互斥锁sync.Mutex, 读写锁sync.RWMutex, 遗憾的是gloang官方包并没有自旋锁,当然可以使用atomic来模拟自旋锁
1 2 3 4 5 6 7 8 9
| func (m *Mutex) Lock() func (m *Mutex) Unlock()
func (rw *RWMutex) RLock() func (rw *RWMutex) RUnlock() func (rw *RWMutex) Lock() func (rw *RWMutex) Unlock()
|
2. Sync.WaitGroup
sync包中WaitGroup 用于等待一组 goroutine 结束,用法很简单。它有三个方法:
1 2 3
| func (wg *WaitGroup) Add(delta int) //增加wait的goroutine个数 func (wg *WaitGroup) Done() //减少wait的goroutine个数,被等待进程结束调用 func (wg *WaitGroup) Wait() //等待结束,计数为0是,唤醒
|
注意,wg.Add() 方法一定要在goroutine开始前执行
3. Sync.Cond
Cond 实现一个条件变量,即等待或宣布事件发生的 goroutines 的会合点
1 2 3 4
| func NewCond(l Locker) *Cond func (c *Cond) Broadcast() func (c *Cond) Signal() func (c *Cond) Wait()
|
sync.Cond使用比较复杂,这里给出一个使用例子
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
| package main
import ( "fmt" "sync" "time" )
func main() { var cond = sync.NewCond(new(sync.Mutex)) for i := 0; i < 5; i++ { go func(x int) { cond.L.Lock() defer cond.L.Unlock() cond.Wait() fmt.Printf("id:%d, time:%d\n", x, time.Now().Unix()) }(i) }
time.Sleep(time.Second) cond.Signal() time.Sleep(2 * time.Second) cond.Signal() time.Sleep(2 * time.Second) cond.Broadcast() time.Sleep(time.Second) }
|
运行结果如下
4. Sync.Pool
Golang中Sync.Pool可以作为对象池使用,且是线程安全的
1 2 3 4 5 6 7 8
| type Demo struct{} pool := sync.Pool{ New: func() interface{} { return &Demo{} }, } func (p *Pool) Get() interface{} func (p *Pool) Put(x interface{}) //释放对象
|
5. Sync.Once
Golang中经常有场景需要初始化全局变量,但有可能存在并发问题,这里就使用到了sync.Once
1
| func (o *Once) Do(f func())
|