1-3.【GCD】DispatchQueue 的底层数据结构是什么?
它是一个复杂的 C 结构体,集成了任务队列、线程管理、性能优化等多个子系统。
核心数据结构:dispatch_queue_s
// libdispatch 源码中的核心结构(简化)
struct dispatch_queue_s {
// 1. 基础头部信息(所有 dispatch 对象共享)
struct dispatch_object_s _as_do[0]; // 转换为 dispatch_object
struct dispatch_queue_s *_as_dq[0]; // 转换为 dispatch_queue
// 2. 队列标识信息
const struct dispatch_queue_vtable_s *vtable; // 虚函数表(多态)
const char *dq_label; // 队列标签(我们设置的 label)
uint16_t dq_width; // 并发宽度(串行为1)
uint32_t dq_serialnum; // 序列号(唯一标识)
// 3. 目标队列和层次结构
struct dispatch_queue_s *dq_targetq; // 目标队列(优先级继承)
uintptr_t dq_targetq_override; // 目标队列覆盖(QoS 传播)
// 4. 任务队列管理
union {
struct dispatch_queue_specific_head_s *dq_specific_head;
struct dispatch_source_refs_s *ds_refs;
} _dq_specific;
// 5. 同步原语
struct dispatch_object_s *volatile dq_items_tail; // 任务队列尾部
struct dispatch_object_s *volatile dq_items_head; // 任务队列头部
uint32_t dq_atomic_flags; // 原子标志位
// 6. 线程池和性能管理
struct dispatch_continuation_s *volatile dq_last; // 最后执行的任务
uint32_t dq_side_specific_ints; // 性能计数器
pthread_priority_t dq_priority; // 优先级缓存
};
详细结构解析
1. 多态设计:dispatch_object
// 所有 GCD 对象的基类
struct dispatch_object_s {
_DISPATCH_OBJECT_HEADER(object); // 头部宏,包含引用计数等
};
// DispatchQueue 通过以下宏实现多态
#define _DISPATCH_QUEUE_CLASS_HEADER(queue_label, ...) \
_DISPATCH_OBJECT_HEADER(queue) \
const char *dq_label; \
uint16_t dq_width;
// 这使得:
dispatch_queue_t queue = dispatch_queue_create("com.test", NULL);
dispatch_object_t obj = (dispatch_object_t)queue; // 可以向上转型
2. 任务队列:双向链表
// 实际存储任务的结构
struct dispatch_continuation_s {
struct dispatch_object_s dc_do; // 对象头部
dispatch_function_t dc_func; // 执行函数
void *dc_ctxt; // 上下文参数
void *dc_data; // 额外数据
void *dc_other; // 关联数据
// 链表指针
struct dispatch_continuation_s *volatile dc_next;
struct dispatch_continuation_s *dc_prev;
// 队列关联
struct dispatch_queue_s *dc_queue; // 所属队列
};
// 队列如何管理任务
struct dispatch_queue_s {
// ...
struct dispatch_continuation_s *dq_items_head; // 队头
struct dispatch_continuation_s *dq_items_tail; // 队尾
uint32_t dq_nitems; // 任务计数
};
3. 队列层次结构
// 队列间的父子关系(目标队列机制)
struct dispatch_queue_hierarchy_s {
dispatch_queue_t dqh_queue; // 当前队列
dispatch_queue_t dqh_target; // 目标队列
uintptr_t dqh_override; // QoS 覆盖
uint16_t dqh_priority; // 优先级
};
// 示例:
// 自定义队列 → 全局队列 → 根队列
// com.test.queue → com.apple.root.default-qos → kernel
4. 性能优化结构
// 队列的侧面(side)数据结构
struct dispatch_queue_side_s {
// 用于性能优化的缓存
uint64_t dq_side_timer; // 定时器相关
uint64_t dq_side_wlh; // 工作循环句柄
uint32_t dq_side_bits; // 状态位
};
// 队列特定数据(dispatch_queue_set_specific/get_specific)
struct dispatch_queue_specific_head_s {
struct dispatch_specific_queue_s *dsq_next;
void *dsq_data; // 用户设置的数据
uintptr_t dsq_key; // 键值
};
不同队列类型的内部差异
1. 全局队列(Global Queue)
// 全局队列有特殊结构
struct dispatch_queue_global_s {
struct dispatch_queue_s _as_dq[0]; // 基础队列部分
// 全局队列特有
int dgq_priority; // 优先级索引
unsigned int dgq_flags; // 标志位
// 共享线程池引用
struct dispatch_pthread_root_queue_s *dgq_thread_pool;
struct dispatch_workloop_s *dgq_wlh; // 工作循环
};
2. 主队列(Main Queue)
// 主队列的特殊处理
struct dispatch_queue_main_s {
struct dispatch_queue_s _as_dq[0];
// 与 RunLoop 集成
CFRunLoopRef _dq_runloop; // 关联的 RunLoop
CFRunLoopSourceRef _dq_runloop_source; // 事件源
// 串行执行保证
pthread_t _dq_main_thread; // 主线程标识
uint32_t _dq_main_flags; // 主队列标志
};
3. 并发队列 vs 串行队列
// 区别主要在 dq_width 字段:
struct dispatch_queue_s {
uint16_t dq_width; // 并发宽度
// 值为 1:串行队列(DISPATCH_QUEUE_SERIAL)
// 值 > 1:并发队列(DISPATCH_QUEUE_CONCURRENT)
// 特殊值:DISPATCH_QUEUE_WIDTH_MAX(并发无限)
};
// 并发队列还有额外的管理结构
struct dispatch_queue_concurrent_s {
struct dispatch_queue_s _as_dq[0];
// 用于并发控制
os_unfair_lock _dq_lock; // 内部锁
uint32_t _dq_running; // 正在运行的任务数
uint32_t _dq_max_running; // 最大并发数
};
内存布局示例
// DispatchQueue 在内存中的大致布局
+-----------------------------------+
| dispatch_object_s header | ← 引用计数、类型信息等
|-----------------------------------|
| vtable pointer | ← 虚函数表(决定队列类型行为)
|-----------------------------------|
| dq_label ("com.example.queue") | ← 队列标签指针
|-----------------------------------|
| dq_width (1 或 n) | ← 并发宽度
|-----------------------------------|
| dq_serialnum (0x1234) | ← 序列号
|-----------------------------------|
| dq_targetq (指向全局队列) | ← 目标队列指针
|-----------------------------------|
| dq_items_head → [任务1] → [任务2] | ← 任务链表头
| dq_items_tail → [任务n] | ← 任务链表尾
|-----------------------------------|
| dq_last (最后执行的任务指针) | ← 性能优化
|-----------------------------------|
| dq_priority (QoS 值) | ← 优先级缓存
+-----------------------------------+
队列创建过程
创建自定义队列时的内部操作:
dispatch_queue_t dispatch_queue_create(const char *label,
dispatch_queue_attr_t attr) {
// 1. 分配内存
struct dispatch_queue_s *dq = calloc(1, sizeof(struct dispatch_queue_s));
// 2. 设置基本字段
dq->dq_label = label ? strdup(label) : NULL;
dq->dq_serialnum = dispatch_atomic_inc(&g_serialnum); // 全局递增
// 3. 根据属性设置并发宽度
if (attr == DISPATCH_QUEUE_SERIAL || attr == NULL) {
dq->dq_width = 1; // 串行
} else if (attr == DISPATCH_QUEUE_CONCURRENT) {
dq->dq_width = DISPATCH_QUEUE_WIDTH_MAX; // 并发
}
// 4. 设置目标队列(通常是全局队列)
dq->dq_targetq = _dispatch_get_root_queue(qos, overcommit);
// 5. 设置虚函数表
if (dq->dq_width == 1) {
dq->vtable = &_dispatch_queue_serial_vtable;
} else {
dq->vtable = &_dispatch_queue_concurrent_vtable;
}
// 6. 初始化任务链表
dq->dq_items_head = dq->dq_items_tail = NULL;
return dq;
}
任务执行流程数据结构
// 任务提交和执行涉及的数据结构
struct dispatch_queue_workloop_s {
// 工作循环(每个线程一个)
pthread_workqueue_t dqw_workqueue; // 底层工作队列
uint32_t dqw_refcnt; // 引用计数
uint16_t dqw_qos; // QoS 级别
// 任务调度
struct dispatch_continuation_s *dqw_head;
struct dispatch_continuation_s *dqw_tail;
// 线程池管理
uint32_t dqw_thread_pool_size; // 线程池大小
uint32_t dqw_thread_pool_active; // 活跃线程数
};
调试信息
// 可以通过私有 API 查看内部结构(仅调试)
extension DispatchQueue {
func debugInfo() {
let queue = self as AnyObject
// 使用 Objective-C 运行时查看内部结构
let ivars = class_copyIvarList(object_getClass(queue), nil)
while let ivar = ivars?.pointee {
let name = String(cString: ivar_getName(ivar)!)
print("Ivar: (name)")
}
}
}
// 或者使用 LLDB 调试
(lldb) po (id)0x600003d6c040 // 假设这是队列地址
// 可以看到内部字段(如果符号可用)
性能优化特性
1. 内联缓存
struct dispatch_queue_cache_s {
// 缓存最近使用的队列
struct dispatch_queue_s *dqc_queues[DISPATCH_QUEUE_CACHE_SIZE];
uint32_t dqc_hits; // 缓存命中次数
uint32_t dqc_misses; // 缓存未命中
};
2. 优先级继承
struct dispatch_queue_priority_s {
uint16_t dqp_priority; // 当前优先级
uint16_t dqp_inherited; // 继承的优先级
struct dispatch_queue_s *dqp_source; // 优先级来源队列
};
总结
DispatchQueue 的底层数据结构:
- 复杂但高效:多层结构体设计,兼顾灵活性和性能
- 基于对象模型:所有 dispatch 对象共享基类,实现多态
- 链表管理任务:使用双向链表存储待执行任务
- 层次化设计:队列有目标队列,形成优先级继承链
- 类型特定扩展:不同队列类型有不同字段和虚函数表
- 性能优化密集:包含大量缓存、计数器和优化字段
简单来说:DispatchQueue 在底层是一个精心设计的任务调度引擎,它:
- 用结构体表示队列(而非类)
- 用链表管理任务
- 用虚函数表实现不同队列类型的行为
- 用目标队列机制实现优先级继承
- 高度优化以减少内存占用和提高性能
这种设计使得 GCD 能够在极小的开销下处理数千个队列和数百万个任务调度。
👉 追问:任务是如何入队、出队的?
任务入队出队是 GCD 的核心机制,涉及原子操作、无锁队列、优先级调度等多个复杂系统。
核心数据结构关系
// 简化版数据结构关系
struct dispatch_queue_s {
// 任务链表(无锁队列)
struct dispatch_continuation_s *volatile dq_items_head; // 队头
struct dispatch_continuation_s *volatile dq_items_tail; // 队尾
uint32_t dq_nitems; // 任务计数
// 线程池引用
struct dispatch_queue_workloop_s *dq_wlh; // 工作循环
};
struct dispatch_continuation_s {
// 任务数据和函数指针
dispatch_function_t dc_func; // 要执行的函数
void *dc_ctxt; // 上下文参数
// 链表指针(双向链表)
struct dispatch_continuation_s *volatile dc_next;
struct dispatch_continuation_s *dc_prev;
// 标记信息
uintptr_t dc_flags; // 标志位(同步/异步/屏障等)
};
1. 入队过程(Enqueue)
异步任务入队(dispatch_async)
// 用户调用
queue.async {
print("任务执行")
}
// 内部处理流程
func dispatch_async(queue: dispatch_queue_t, block: @escaping () -> Void) {
// 1. 封装任务
let continuation = _dispatch_continuation_alloc()
continuation.dc_func = _dispatch_call_block_and_release
continuation.dc_ctxt = Block_copy(block) // 复制block到堆上
// 2. 获取队列状态
let old_state = queue.dq_state
// 3. 尝试快速路径(无锁操作)
if _dispatch_queue_try_acquire_async(queue) {
// 快速路径:队列空闲,直接调度
_dispatch_continuation_schedule(queue, continuation)
return
}
// 4. 慢速路径:需要加锁或队列繁忙
_dispatch_queue_push(queue, continuation)
}
详细入队步骤
// 实际入队函数
void _dispatch_queue_push(dispatch_queue_t dq,
dispatch_continuation_t dc) {
// 步骤1:设置任务状态
dc->dc_queue = dq; // 关联队列
dc->dc_flags = ASYNC; // 标记为异步
// 步骤2:原子操作将任务加入链表尾部
dispatch_continuation_t prev_tail;
do {
prev_tail = dq->dq_items_tail;
dc->dc_prev = prev_tail; // 设置前驱
} while (!os_atomic_cmpxchg(&dq->dq_items_tail,
prev_tail,
dc,
relaxed));
// 步骤3:更新前一个节点的next指针
if (prev_tail) {
prev_tail->dc_next = dc; // 连接链表
} else {
// 这是第一个任务,更新头指针
dq->dq_items_head = dc;
}
// 步骤4:原子递增任务计数
os_atomic_inc(&dq->dq_nitems, relaxed);
// 步骤5:唤醒工作线程(如果需要)
_dispatch_queue_wakeup(dq);
}
屏障任务特殊处理
// 屏障任务的入队
void _dispatch_barrier_async(dispatch_queue_t dq,
dispatch_block_t block) {
dispatch_continuation_t dc = _dispatch_continuation_alloc();
dc->dc_func = _dispatch_call_block_and_release;
dc->dc_ctxt = Block_copy(block);
dc->dc_flags = BARRIER; // 关键:设置屏障标志
// 屏障任务需要特殊处理:
// 1. 插入到队列末尾
// 2. 标记队列进入"屏障模式"
// 3. 等待前面所有任务完成
_dispatch_queue_push_barrier(dq, dc);
// 更新队列状态
dq->dq_atomic_flags |= DISPATCH_QUEUE_IN_BARRIER;
}
2. 出队过程(Dequeue)
工作线程取任务
// 工作线程的主循环
void *_dispatch_worker_thread(void *context) {
dispatch_queue_t dq = (dispatch_queue_t)context;
while (1) {
// 步骤1:获取下一个任务
dispatch_continuation_t dc = _dispatch_queue_pop(dq);
if (dc) {
// 步骤2:执行任务
_dispatch_continuation_invoke(dq, dc);
// 步骤3:任务完成后处理
_dispatch_continuation_free(dc);
} else {
// 步骤4:无任务,可能休眠或处理其他队列
_dispatch_worker_yield_or_exit(dq);
}
}
return NULL;
}
详细出队实现
// 从队列弹出任务
dispatch_continuation_t _dispatch_queue_pop(dispatch_queue_t dq) {
// 步骤1:检查队列状态
if (dq->dq_nitems == 0) {
return NULL; // 队列为空
}
// 步骤2:处理串行队列(简单)
if (dq->dq_width == 1) { // 串行队列
return _dispatch_queue_pop_serial(dq);
}
// 步骤3:处理并发队列(复杂)
return _dispatch_queue_pop_concurrent(dq);
}
// 串行队列出队(简单FIFO)
dispatch_continuation_t _dispatch_queue_pop_serial(dispatch_queue_t dq) {
// 原子操作获取队头
dispatch_continuation_t head;
do {
head = dq->dq_items_head;
if (!head) return NULL; // 队列为空
// 尝试将头指针指向下一个任务
} while (!os_atomic_cmpxchg(&dq->dq_items_head,
head,
head->dc_next,
acquire));
// 如果队列变空,清空尾指针
if (head->dc_next == NULL) {
dq->dq_items_tail = NULL;
}
// 更新任务计数
os_atomic_dec(&dq->dq_nitems, relaxed);
// 清理链表指针
head->dc_next = NULL;
head->dc_prev = NULL;
return head;
}
// 并发队列出队(多线程安全)
dispatch_continuation_t _dispatch_queue_pop_concurrent(dispatch_queue_t dq) {
// 使用原子操作+重试机制
dispatch_continuation_t task = NULL;
bool acquired = false;
while (!acquired) {
// 原子读取队头
dispatch_continuation_t old_head = dq->dq_items_head;
if (!old_head) {
return NULL; // 队列为空
}
// 尝试获取任务所有权
acquired = os_atomic_cmpxchg(&dq->dq_items_head,
old_head,
old_head->dc_next,
acquire);
if (acquired) {
task = old_head;
// 如果这是最后一个任务
if (task->dc_next == NULL) {
// 需要原子更新尾指针
os_atomic_store(&dq->dq_items_tail, NULL, relaxed);
}
}
// 如果失败,说明其他线程抢先获取了,重试
}
os_atomic_dec(&dq->dq_nitems, relaxed);
task->dc_next = NULL;
task->dc_prev = NULL;
return task;
}
3. 任务执行流程
任务执行函数
// 执行任务的函数
void _dispatch_continuation_invoke(dispatch_queue_t dq,
dispatch_continuation_t dc) {
// 步骤1:保存当前队列上下文
dispatch_queue_t old_dq = _dispatch_thread_getspecific(dispatch_queue_key);
_dispatch_thread_setspecific(dispatch_queue_key, dq);
// 步骤2:设置线程名字(便于调试)
if (dq->dq_label) {
pthread_setname_np(dq->dq_label);
}
// 步骤3:执行任务函数
dc->dc_func(dc->dc_ctxt);
// 步骤4:恢复之前的队列上下文
_dispatch_thread_setspecific(dispatch_queue_key, old_dq);
// 步骤5:如果是同步任务,发送信号
if (dc->dc_flags & SYNC) {
_dispatch_semaphore_signal(dc->dc_semaphore);
}
}
屏障任务的特殊执行
// 屏障任务的执行
void _dispatch_barrier_execute(dispatch_queue_t dq,
dispatch_continuation_t dc) {
// 步骤1:等待队列中所有前置任务完成
while (dq->dq_running > 0) {
// 忙等待或让出CPU
_dispatch_hardware_pause();
}
// 步骤2:执行屏障任务(独占执行)
_dispatch_continuation_invoke(dq, dc);
// 步骤3:清除屏障标志
dq->dq_atomic_flags &= ~DISPATCH_QUEUE_IN_BARRIER;
// 步骤4:唤醒等待的后续任务
_dispatch_queue_wakeup_next(dq);
}
4. 性能优化机制
任务批处理
// 批量处理任务(减少锁开销)
void _dispatch_queue_drain(dispatch_queue_t dq) {
// 尝试一次性取出多个任务
dispatch_continuation_t batch[16];
int count = 0;
// 批量出队
for (int i = 0; i < 16; i++) {
dispatch_continuation_t dc = _dispatch_queue_pop_fast(dq);
if (!dc) break;
batch[count++] = dc;
}
if (count == 0) return;
// 批量执行
for (int i = 0; i < count; i++) {
_dispatch_continuation_invoke(dq, batch[i]);
_dispatch_continuation_free(batch[i]);
}
}
工作窃取(Work Stealing)
// 当线程空闲时,尝试从其他队列窃取任务
dispatch_continuation_t _dispatch_worksteal(void) {
// 步骤1:获取当前线程的工作队列
dispatch_queue_t current_queue = _dispatch_thread_get_queue();
// 步骤2:遍历全局队列列表
for (int i = 0; i < global_queue_count; i++) {
dispatch_queue_t target = global_queues[i];
// 跳过自己的队列和空队列
if (target == current_queue) continue;
if (target->dq_nitems == 0) continue;
// 步骤3:尝试窃取任务
dispatch_continuation_t stolen = _dispatch_queue_try_steal(target);
if (stolen) {
return stolen; // 窃取成功
}
}
return NULL; // 没有可窃取的任务
}
5. 同步任务特殊处理
dispatch_sync 的实现
void dispatch_sync(dispatch_queue_t dq, dispatch_block_t block) {
// 优化:如果当前已经在目标队列上,直接执行
if (_dispatch_queue_is_current(dq)) {
block();
return;
}
// 创建同步任务结构
struct dispatch_sync_context_s {
dispatch_semaphore_t sema;
dispatch_block_t block;
bool done;
} context;
context.sema = dispatch_semaphore_create(0);
context.block = block;
context.done = false;
// 创建任务
dispatch_continuation_t dc = _dispatch_continuation_alloc();
dc->dc_func = _dispatch_sync_invoke;
dc->dc_ctxt = &context;
dc->dc_flags = SYNC;
dc->dc_semaphore = context.sema;
// 入队
_dispatch_queue_push(dq, dc);
// 等待任务完成
dispatch_semaphore_wait(context.sema, DISPATCH_TIME_FOREVER);
// 检查是否成功执行
if (!context.done) {
// 发生错误
dispatch_panic("dispatch_sync failed");
}
}
// 同步任务执行函数
static void _dispatch_sync_invoke(void *ctxt) {
struct dispatch_sync_context_s *ctx = ctxt;
ctx->block();
ctx->done = true;
}
6. 优先级处理
QoS 传播和提升
// 处理任务的优先级
void _dispatch_queue_adjust_priority(dispatch_queue_t dq,
dispatch_continuation_t dc) {
// 获取任务的 QoS
qos_class_t task_qos = _dispatch_continuation_get_qos(dc);
// 如果任务优先级高于队列当前优先级
if (task_qos > dq->dq_priority) {
// 提升队列优先级
qos_class_t old_qos = dq->dq_priority;
dq->dq_priority = task_qos;
// 重新调度队列中的工作线程
_dispatch_queue_reschedule(dq, old_qos, task_qos);
}
// 设置执行线程的 QoS
pthread_set_qos_class_self_np(task_qos, 0);
}
完整流程示例
// 模拟一个任务从提交到完成的完整流程
func exampleTaskLifecycle() {
let queue = DispatchQueue(label: "com.example", attributes: .concurrent)
// 用户提交任务
queue.async {
print("任务执行开始")
sleep(1)
print("任务执行结束")
}
// 内部流程:
// 1. async() 创建 dispatch_continuation_t
// 2. 原子操作将任务添加到 queue.dq_items_tail
// 3. queue.dq_nitems 原子递增
// 4. _dispatch_queue_wakeup() 唤醒工作线程
// 5. 工作线程从 queue.dq_items_head 取出任务
// 6. 调用 dc_func(dc_ctxt) 执行任务
// 7. 任务完成,dc 被释放
// 8. 工作线程继续取下一个任务或休眠
}
7. 内存管理优化
任务缓存池
// 避免频繁分配释放 dispatch_continuation_t
struct dispatch_continuation_cache_s {
dispatch_continuation_t free_list; // 空闲列表
uint32_t count; // 缓存数量
os_unfair_lock lock; // 保护锁
};
// 获取一个任务结构(优先从缓存取)
dispatch_continuation_t _dispatch_continuation_alloc(void) {
dispatch_continuation_cache_t cache = &g_continuation_cache;
// 尝试从缓存获取
os_unfair_lock_lock(&cache->lock);
if (cache->free_list) {
dispatch_continuation_t dc = cache->free_list;
cache->free_list = dc->dc_next;
cache->count--;
os_unfair_lock_unlock(&cache->lock);
// 清零复用
memset(dc, 0, sizeof(struct dispatch_continuation_s));
return dc;
}
os_unfair_lock_unlock(&cache->lock);
// 缓存为空,分配新的
return calloc(1, sizeof(struct dispatch_continuation_s));
}
// 释放任务结构(放入缓存)
void _dispatch_continuation_free(dispatch_continuation_t dc) {
dispatch_continuation_cache_t cache = &g_continuation_cache;
os_unfair_lock_lock(&cache->lock);
if (cache->count < DISPATCH_CONTINUATION_CACHE_MAX) {
// 放入缓存
dc->dc_next = cache->free_list;
cache->free_list = dc;
cache->count++;
os_unfair_lock_unlock(&cache->lock);
} else {
os_unfair_lock_unlock(&cache->lock);
free(dc); // 缓存已满,直接释放
}
}
总结
任务入队出队的核心机制:
入队过程:
-
封装任务:将block封装成
dispatch_continuation_t - 原子操作:使用CAS(Compare-And-Swap)将任务添加到链表尾部
- 唤醒机制:如果需要,唤醒工作线程处理任务
- 优先级处理:根据任务QoS调整队列优先级
出队过程:
- 原子竞争:多个工作线程竞争获取任务(无锁队列)
- 批量处理:可能一次性取出多个任务减少开销
- 工作窃取:空闲线程可以从其他队列窃取任务
- 屏障处理:屏障任务确保前后任务不交错执行
关键优化:
- 无锁设计:使用原子操作避免锁竞争
- 缓存复用:重用任务结构体减少内存分配
- 批量处理:减少上下文切换开销
- 优先级继承:高优先级任务能更快执行
- 工作窃取:提高CPU利用率
简单比喻:
- 入队 像"快递站收件":你提交包裹(任务),快递站记录到清单(队列),通知快递员(线程)来取
- 出队 像"快递员派件":快递员从清单取包裹,派送(执行),完成后标记完成
- GCD 像"智能调度系统":动态分配快递员,优化路线,处理急件优先
这种设计使得 GCD 能够以极低的延迟处理数百万级的任务调度,同时保持高吞吐量和低CPU占用。