前言
直接上干货
┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐
│ 场景特征 │ 推荐方案 │ 原因 │ 示例 │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ 读多写少 │ Barrier │ 读取并发性能好 │ 弹幕、评论 │
│ 高并发读取 │ │ 写入一致性保证 │ 股票行情 │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ 读写均衡 │ Serial Queue │ 实现简单 │ 配置管理 │
│ 低并发 │ │ 无死锁风险 │ 用户设置 │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ iOS 13+ │ Actor │ 现代安全 │ 新项目 │
│ 新项目 │ │ 编译时检查 │ SwiftUI应用 │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ 极致性能 │ 读写锁 │ 接近无锁性能 │ 高频交易 │
│ 系统级开发 │ (pthread) │ 精细控制 │ 数据库引擎 │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ 简单场景 │ Lock │ 实现简单 │ 单线程访问 │
│ 低并发访问 │ │ 强一致性 │ 启动配置 │
└─────────────────┴─────────────────┴─────────────────┴─────────────────┘对比各个方案
┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐
│ 工具 │ 现实类比 │ 核心功能 │ 适用场景 │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ 串行队列 │ 单行道 │ 任务排队执行 │ 简单顺序执行 │
│ (Serial Queue) │ (一次一辆车) │ │ │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ Barrier │ 收费站 │ 读写分离 │ 读多写少 │
│ │ (多入口单出口) │ │ │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ 锁 (Lock) │ 单间厕所 │ 完全互斥 │ 强一致性 │
│ │ (一次一个人) │ │ │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ 信号量 │ 停车场 │ 控制并发数量 │ 资源池限制 │
│ (Semaphore) │ (有限车位) │ │ │
└─────────────────┴─────────────────┴─────────────────┴─────────────────┘barrier
Barrier 最适合的经典场景:
- 缓存系统:图片缓存、API响应缓存
- 状态管理:购物车、用户配置、游戏状态
- 网络数据:实时数据同步、WebSocket消息
- UI组件:主题管理、数据源、配置
- 持久化:日志系统、数据库连接池
- 协作应用:实时编辑、多用户状态
Barrier 的本质是读写锁的实现,图形化表示 Barrier 状态机:
┌─────────┐ 开始读取 ┌─────────┐ 最后一个读者完成 ┌─────────┐
│ 空闲 │ ──────────> │ 读取中 │ ──────────────> │ 空闲 │
│ (Idle) │ │(Reading)│ │ (Idle) │
└─────────┘ └─────────┘ └─────────┘
^ │ │
│ Barrier完成 │ 请求Barrier │
└──────────────────────┘ │
┌─────────┐ │
│Barrier │ <───────────────────┘
│等待中 │
│(Pending)│
└─────────┘
│ 所有读者完成
\/
┌─────────┐
│Barrier │
│执行中 │
│(Executing)
└─────────┘如何决策
遇到并发问题 -> 问自己以下几个问题:
1. 需要控制任务执行顺序吗?
├─ 是 -> 使用串行队列 (Serial Queue)
└─ 否 -> 进入问题2
2. 有共享数据需要读写吗?
├─ 是 -> 进入问题3
└─ 否 -> 进入问题4
3. 读操作多还是写操作多?
├─ 读多写少 -> 使用 Barrier (读写锁)
├─ 读写均衡 -> 使用锁 (Lock)
└─ 主要是写 -> 使用锁 (Lock)
4. 需要限制并发任务数量吗?
├─ 是 -> 使用信号量 (Semaphore)
└─ 否 -> 可能不需要同步工具