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