前言

直接上干货

┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐
│     场景特征     │     推荐方案     │     原因         │     示例        │
├─────────────────┼─────────────────┼─────────────────┼─────────────────┤
│  读多写少       │  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)
   └─ 否 -> 可能不需要同步工具