跳到主要内容

GCD 详解

问题

GCD 的核心概念是什么?DispatchQueue 的串行和并发有什么区别?常用 API 有哪些?

答案

核心概念

GCD(Grand Central Dispatch) 是 Apple 提供的 C 语言并发框架,基于线程池自动管理线程。开发者只需将任务提交到队列,GCD 负责调度执行。

队列类型

串行队列并发队列
执行方式一个接一个(FIFO)多个任务可同时执行
创建DispatchQueue(label: "com.app.serial")DispatchQueue(label: "com.app.concurrent", attributes: .concurrent)
系统提供主队列 DispatchQueue.main全局队列 DispatchQueue.global()

sync vs async

let queue = DispatchQueue(label: "com.app.serial")

// async:不等待任务完成,立即返回
queue.async {
print("异步执行") // 在 queue 的线程上
}
print("立即执行") // 先打印

// sync:等待任务完成才继续
queue.sync {
print("同步执行") // 在 queue 的线程上
}
print("等任务完成后才执行")
死锁:主队列 sync
// ❌ 在主线程上对主队列 sync → 死锁!
DispatchQueue.main.sync {
print("永远不会执行")
}

主线程在等 sync 完成 → sync 的任务需要在主线程执行 → 主线程在等 → 死锁

常用 API

DispatchGroup

let group = DispatchGroup()

group.enter()
fetchUser { user in
// ...
group.leave()
}

group.enter()
fetchPosts { posts in
// ...
group.leave()
}

group.notify(queue: .main) {
// 两个请求都完成后执行
updateUI()
}

DispatchSemaphore

let semaphore = DispatchSemaphore(value: 3) // 最多 3 个并发

for url in urls {
DispatchQueue.global().async {
semaphore.wait() // 信号量 -1,为 0 时阻塞
download(url) {
semaphore.signal() // 信号量 +1
}
}
}

DispatchWorkItem(可取消任务)

var workItem: DispatchWorkItem?

workItem = DispatchWorkItem {
guard !(workItem?.isCancelled ?? true) else { return }
// 执行搜索
performSearch(query)
}

// 延迟执行(防抖)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: workItem!)

// 取消
workItem?.cancel()

QoS 优先级

DispatchQueue.global(qos: .userInteractive)  // 最高:UI 相关
DispatchQueue.global(qos: .userInitiated) // 高:用户发起
DispatchQueue.global(qos: .default) // 默认
DispatchQueue.global(qos: .utility) // 低:长时间任务
DispatchQueue.global(qos: .background) // 最低:不急

常见面试问题

Q1: 串行队列 async 和 sync 的区别?

答案

  • async:将任务放入队列后立即返回,不会阻塞当前线程
  • sync:将任务放入队列后等待任务完成才返回,阻塞当前线程
  • 无论 sync 还是 async,在串行队列上任务都是一个接一个执行

Q2: 如何实现并发数量限制?

答案

  1. DispatchSemaphoreDispatchSemaphore(value: maxConcurrency)
  2. OperationQueuequeue.maxConcurrentOperationCount = 3
  3. Swift Concurrency:TaskGroup + semaphore 模式

Q3: GCD 线程数量有限制吗?

答案:GCD 的线程池有上限(大约 64 个工作线程)。如果大量 sync 操作阻塞线程,可能导致线程爆炸(Thread Explosion),影响性能甚至死锁。应避免在 GCD 中使用 sync 或信号量阻塞。

相关链接