概述
为什么会出现
如果进程同时只能处理一件事,在等待资源(耗时计算、IO)时也不能处理其他任务,会导致工作效率低,cpu空闲时间较长,为了能充分利用cpu加快任务处理效率,就需要多线程处理任务
遇到问题
- 公共资源竞争
- 线程间数据交互
- 任务编排
原因
- 逻辑不是原子操作
- 系统优化,指令重排序
- 缓存,数据没马上同步
解决方案
- 临界区加锁,加锁区变成原子操作,同时不会指令重排
使用会引发的问题与优化
- 死锁,不同线程死锁,锁重入问题
- 公平问题,锁饥饿
- 自旋
- try lock
工具
- race,查找存在竞争的资源 go run -race xxx.go,编译插入检查代码
- vet 工具检查死锁问题,代码静态分析
基本并发原语
Mutex 锁
RWMutex 读写锁
Waitgroup
Cond
wait/notify模型,用Waitgroup或者channel替换,基本不会使用
Once
可以用来执行且仅仅执行一次动作,常常用于单例对象的初始化场景
var once sync.Once
once.Do(f func)
Pool
Context
原子操作
Channel
扩展并发原语
信号量、SingleFlight、循环栅栏、ErrGroup
分布式并发原语
分布式并发原语是应对大规模的应用程序中并发问题的并发类型。我主要会介绍使用 etcd 实现的一些分布式并发原语,比如 Leader 选举、分布式互斥锁、分布式读写锁、分布式队列等,在处理分布式场景的并发问题时,特别有用