同步工具选择
为什么需要同步工具?
- 同步: 协调多个 goroutine 的执行顺序或共享数据访问,避免读到一半状态或互相覆盖写入;
- 数据竞争入口: 定义与检测方式见并发设计,本篇只承担工具选择;
- 选择起点: 先判断目标是“保护共享状态”“等待任务完成”还是“只初始化一次”,再选择工具;
如何根据问题选择工具?
| 工具 | 优先使用场景 |
|---|---|
sync/atomic | 简单计数器、状态标记的原子读写 |
sync.Mutex | 共享变量, map 或多项状态, 复合不变量的互斥访问 |
sync.RWMutex | 共享数据读多写少, 需要允许多个读取并发执行 |
sync.WaitGroup | 等待多个并发任务结束 |
sync.Once | 只执行一次的初始化 |
- 选择示例: 并发请求各自累加次数可用 atomic;账户扣款与余额校验必须作为一个整体时用 Mutex;批量请求收尾用 WaitGroup;固定配置初始化用 Once;
保护一份共享状态? → 先考虑 Mutex
只是一个计数的增减?→ 可评估 atomic
只等所有任务结束? → WaitGroup
初始化必须最多一次?→ Once
需要交接数据或事件?→ channel
选择时容易犯什么错误?
-
atomic 误用: 多个字段必须一起满足业务规则时,分别做原子读写不能保护整体不变量,应使用 Mutex;
-
RWMutex 误用: 读多写少只是候选条件;临界区很短或竞争很低时,普通 Mutex 往往更简单;
-
WaitGroup 边界: 只等待任务完成,不保护任务读写的共享数据;
-
Once 选择入口: 失败重试与资源刷新不适合 Once,具体执行及 panic 规则见Once;
-
channel 选择: 需要传递数据所有权或表达事件顺序时优先考虑 channel,不必把所有并发问题都改成共享内存加锁;
-
组合边界: 等待与互斥是不同责任,同一批任务可以同时需要 WaitGroup 和 Mutex;加一个工具前先指出它保护的状态或建立的完成关系;