Go Concurrent
Go 并发
Go Memory Model
- 保证内存顺序满足 happens-before (因果一致性)
GMP
G: goroutine, M: thread, P: processor
M:N,thread : processor = 1:1
策略
- work stealing:空闲 thread 从其他 thread 的 processor 偷取 goroutine
- hand off:当前 thread 的 goroutine 阻塞时,将 processor 交给其他空闲 thread
生命周期
Goroutine
go runtime 调度,m:n (m 个 goroutine 对应 n 个 OS 线程)
主协程退出,goroutine 退出
Go 高并发
- goroutine 栈空间 2KB, 可伸缩
- 用户态维护一块内存池,不用系统 malloc,也不用频繁切换内核态
- 实现 m:n 调度和上下文切换,减少 goroutine 开销
线程和协程
- 一个内核线程上可以跑多个协程,抢占式调度
- 协程有独立的栈空间,共享堆空间,由用户态协作式调度
Channel
- 用 Channel 实现共享内存,不要用共享内存实现 Channel 😊
- 队列,遵循 CSP 模型,goroutine 间通信
- 无缓冲通道需要同时有发送者和接收者,发送时会阻塞,若无接收者会死锁
select
多路复用,管理 channel
1 | ch:=make(chan T) // 无缓冲通道 |
Context
- goroutine 之间传递上下文
- 请求超时退出 goroutine
sync.Mutex
- 保证只有一个 goroutine 进入临界区访问共享数据,其他 goroutine 等待 mu 释放
- 不可重入
1 | type Mutex struct { |
sync.RWMutex
- 读多写少,一个写锁
Lock()
或多个读锁RLock()
- 写者优先
1 | type RWMutex struct { |
sync.WaitGroup
- 主协程同步 goroutine 任务
- WaitGroup 是结构体,指针传递
name | func |
---|---|
(wg * WaitGroup) Add(n int) | counter + n |
(wg *WaitGroup) Done() | counter - 1 |
(wg *WaitGroup) Wait() | 阻塞至 counter = 0 |
sync.Once
- 一次性操作
sync.Cond
- multi-goroutine 间的通知
- cond 维护 goroutine 等待队列
(&c).Wait()
:cond 加锁时用(&c).Signal()
: 唤醒并移除 cond 队列第一个 goroutine(&c).Broadcast()
: 唤醒并移除 cond 队列所有 goroutine
1 | func main() { |
cover
画师: ノーコピーライトガール
id: 122225604
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 夏霞 🌸!