Go 语言之父 Rob Pike 还有一句经典名言:“不要通过共享内存来通信,应该通过通信来共享内存”。这就奠定了 Go 应用并发设计的主流风格:使用 channel 进行不同 Goroutine 间的通信。

一般情况下,建议优先使用 channel 并发模型进行并发程序设计。

不过,Go 也并没有彻底放弃基于共享内存的并发模型,而是在提供 CSP 并发模型原语的同时,还通过标准库的:

  • sync 包,提供了针对传统的、基于共享内存并发模型的低级同步原语,包括:
    • 互斥锁(sync.Mutex)
    • 读写锁(sync.RWMutex):适合应用在具有一定并发量且读多写少的场合
    • 条件变量(sync.Cond)
  • 并通过 atomic 包提供了原子操作原语等

Mutex 的使用示例:

var mu sync.Mutex

mu.Lock()       // 加锁
doSomething()
mu.Unlock()     // 解锁

RWMutex 的使用示例:

var rwmu sync.RWMutex

rwmu.RLock()    //加读锁
readSomething()
rwmu.RUnlock()  //解读锁

rwmu.Lock()     //加写锁
changeSomething()
rwmu.Unlock()   //解写锁

其实,面向 CSP 并发模型的 channel 原语和面向传统共享内存并发模型的 sync 包提供的原语,已经能够满足 Go 语言应用并发设计中 99.9% 的并发同步需求了。而剩余那 0.1% 的需求,我们可以使用 Go 标准库提供的 atomic 包来实现。

(完。)