1️⃣ 核心结论
DispatchSource 的事件处理 block 并不是直接在内核线程执行的,而是通过 GCD 队列异步派发,事件处理和队列调度紧密耦合:队列决定事件处理执行的线程、顺序和并发性。
换句话说:
- 内核检测到事件 → 通知 GCD → GCD 将事件处理 block 派发到指定队列
- 队列类型(串行 / 并发)直接影响事件处理执行方式
2️⃣ 队列对事件处理的影响
2.1 串行队列
let queue = DispatchQueue(label: "serialQueue")
let source = DispatchSource.makeReadSource(fileDescriptor: fd, queue: queue)
source.setEventHandler {
print("事件处理")
}
source.resume()
-
特点:
- 事件处理在 串行队列上顺序执行
- 同一时间只有一个事件处理 block 执行
- 多个事件同时触发 → 丢到队列尾部顺序执行
✅ 优势:顺序性、互斥保证
2.2 并发队列
let queue = DispatchQueue(label: "concurrentQueue", attributes: .concurrent)
let source = DispatchSource.makeReadSource(fileDescriptor: fd, queue: queue)
source.setEventHandler {
print("事件处理")
}
source.resume()
-
特点:
- 事件处理可以同时在多个线程上执行(并发)
- 队列会调度多个事件处理 block 并行执行
- 事件处理的顺序不保证
✅ 优势:高吞吐量,适合读多写少或高并发场景
3️⃣ 队列调度流程示意
[内核事件触发]
↓
[内核通知 GCD]
↓
[DispatchSource 捕获事件]
↓
[将事件处理 block 派发到目标队列]
↓
[队列调度 block 执行]
-
队列类型决定 block 执行方式:
- 串行队列 → 队列内部串行执行
- 并发队列 → 队列内部并发执行
-
线程选择由队列管理:
- GCD 可以复用现有线程,也可以从线程池取线程
- 不会为每个事件 block 新建线程
4️⃣ 队列与事件处理关系要点
-
队列决定执行线程
- 绑定串行队列 → 独占顺序执行
- 绑定并发队列 → 多线程并行执行
-
队列决定顺序和并发性
- 串行队列保证 FIFO 顺序
- 并发队列可同时执行多个事件 block
-
GCD 提供异步调度
- 内核通知事件 → 不阻塞内核
- 队列异步执行 → 不阻塞触发线程
-
可与 barrier / sync / async 配合
- 可以在串行或并发队列中使用 barrier 保证写操作独占
- DispatchSource 事件 block 是普通 GCD block,可与其他任务组合调度
5️⃣ 总结一句话
DispatchSource 的事件处理依赖队列调度:内核检测事件 → 通知 GCD → 队列派发 block → 队列管理线程、顺序和并发性。队列类型决定了事件处理是串行还是并发执行。