一. 前言
Golang sync包提供了基础的异步操作方法,包括互斥锁Mutex
,执行一次Once
和并发等待组WaitGroup
。
本文主要介绍sync包提供的这些功能的基本使用方法。
- Mutex: 互斥锁
- RWMutex:读写锁
- WaitGroup:并发等待组
- Once:执行一次
- Cond:信号量
- Pool:临时对象池
- Map:自带锁的map
二. sync.Mutex
sync.Mutex
称为互斥锁
,常用在并发编程里面。互斥锁需要保证的是同一个时间段内不能有多个并发协程同时访问某一个资源(临界区)。
sync.Mutex
有2个函数Lock
和UnLock
分别表示获得锁和释放锁。
func (m *Mutex) Lock()
func (m *Mutex) UnLock()
sync.Mutex初始值为UnLock状态,并且sync.Mutex常做为其它结构体的匿名变量使用。
举个例子: 我们经常使用网上支付购物东西,就会出现同一个银行账户在某一个时间既有支出也有收入,那银行就得保证我们余额准确,保证数据无误。
我们可以简单的实现银行的支出和收入来说明Mutex的使用
type Bank struct {
sync.Mutex
balance map[string]float64
}
// In 收入
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
}
// Out 支出
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
}
三. sync.RWMutex
sync.RWMutex
称为读写锁是sync.Mutex
的一种变种,RWMutex来自于计算机操作系统非常有名的读者写者问题
。
sync.RWMutex目的是为了能够支持多个并发协程同时读取某一个资源,但只有一个并发协程能够更新资源。也就是说读和写是互斥的,写和写也是互斥的,读和读是不互斥的。
总结起来如下
- 当有一个协程在读的时候,所有写的协程必须等到所有读的协程结束才可以获得锁进行写操作。
- 当有一个协程在读的时候,所有读的协程不受影响都可以进行读操作。