01
概念
并发是指一个 Go 程序运行在多个 goroutine 中,每个 goroutine 中的事件执行先后顺序无法确定。
02
并发安全
并发安全是指一个可以在串行程序中正确执行的函数,它在并发调用时仍然可以正确执行,那么这个函数是并发安全的。
并发访问一个变量,保证变量并发安全的方法是限制变量只存在于一个 goroutine 中,或维护一个更高层的互斥不变量。
函数并发调用时,不能正常执行的原因主要有死锁、活锁和资源耗尽。
03
竞态
竞态是指一个 Go 程序在多个 goroutine 中按照某些交错顺序执行时,这个 Go 程序无法给出正确的执行结果。
其中数据竞态是竞态的一种,它发生于两个 goroutine 并发读写同一个变量并且至少其中一个 goroutine 是写入时。
避免数据竞态的方法:
- 不修改变量。
- 避免从多个 goroutine 访问同一个变量。
- 允许多个 goroutine 访问同一个变量,但在同一时间只有一个 goroutine 可以访问这个变量。
04
互斥锁
在 Go 语言中,sync 包有一个单独的 Mutex 类型,它支持互斥锁模式。Mutex 类型的 Lock 方法用于获取 token,Unlock 方法用于释放 token。
定义的 Mutex 类型的变量称为互斥量,用来保护共享变量。被互斥量保护的变量声明应该紧接在互斥量的声明之后。
为了防止未执行 Unlock 方法,通常在 Lock 方法后,使用 defer 语句调用 Unlock 方法。
05
读写互斥锁
互斥锁严格锁定读和写,在一些场景中,允许只读操作可以并发执行,但写操作需要获得完全独享的访问权限,sync 包中的 RWMutex 类型包含 RLock 和 RUnlock 方法,可以提供这种功能。RLock 和 RUnlock 方法分别获取和释放一个读锁(共享锁)。
06
延迟初始化
sync 包中有一个 Once 类型,Once 类型只有一个 Do 方法,Once 类型包含一个 bool 变量和一个互斥量,bool 变量记录初始化是否已完成,互斥量负责保护这个 bool 变量和客户端的数据结构。
07
goroutine 与线程
goroutine 与线程的区别:
栈内存:线程的栈内存固定大小 2mb,goroutine 栈内存默认 2KB,但可按需增大和缩小,最大限制是 1GB。
调度:线程由系统内核调度,成本高,速度慢。goroutine 由 Go 调度器调度,Go 调度器只需要关心单个 Go 程序的 goroutine 调度问题,成本低。