从底层线程到高层 Swift Concurrency,用代码带你吃透所有概念
为什么要关心这些概念?
- 响应式 UI:主线程阻塞 = 卡死界面。
- 高性能:多核 CPU 不并行 = 浪费算力。
- 正确性:数据竞争 = 闪退或脏数据。
Thread:程序的最小执行单元
什么是 Thread
一条独立的执行路径,拥有独立的 栈 和 程序计数器,但与其他线程共享进程的内存空间。
手动创建 Thread(仅教学用,生产请用 GCD/Task)
swift
import Foundation
func threadFunction() {
for i in 1...3 {
print("👾 Thread \(Thread.current) count \(i)")
Thread.sleep(forTimeInterval: 0.3)
}
}
let t = Thread {
threadFunction()
}
t.start() // 手动启动线程
⚠️ 直接使用
Thread
成本高、易出错;日常开发请使用 GCD 或 Swift Concurrency。
Concurrency vs. Parallelism:一对容易混淆的孪生兄弟
维度 | Concurrency(并发) | Parallelism(并行) |
---|---|---|
定义 | 交替推进多个任务 | 同时执行多个任务 |
CPU 核数 | 1 核即可 | ≥2 核 |
目的 | 提高响应能力 | 提高吞吐量 |
并发示例(单核交替)
swift
let queue = DispatchQueue(label: "concurrent", attributes: .concurrent)
queue.async { print("🍎 Task A") }
queue.async { print("🍏 Task B") }
单核 CPU 通过时间片轮转交替打印 A/B。
并行示例(多核同时)
swift
DispatchQueue.concurrentPerform(iterations: 4) { i in
print("🔥 Parallel \(i) on \(Thread.current)")
}
4 核机器会真正同时跑 4 条线程。
Swift 中的线程种类
线程 | 用途 | 注意 |
---|---|---|
Main Thread | UI 更新 & 用户交互 | 禁止长时间阻塞 |
Global Queue | 默认后台线程池 | QoS 分级(utility、background ...) |
主线程 & 后台线程实战
swift
// 1. 回到主线程刷新 UI
DispatchQueue.main.async {
label.text = "Loaded"
}
// 2. 后台线程做重活
DispatchQueue.global(qos: .userInitiated).async {
let img = self.resize(image: bigImage)
DispatchQueue.main.async { imageView.image = img }
}
Thread Safety:别让数据"赛车"
问题示例:数据竞争
swift
class UnsafeCounter {
var value = 0
func increment() { value += 1 }
}
在多线程环境下 value += 1
可能丢失更新(读-改-写非原子)。
解决方案速查表
技术 | 适用场景 | 示例 |
---|---|---|
NSLock | 低层临界区 | 见下方代码 |
串行 DispatchQueue | 顺序执行任务 | DispatchQueue(label: "serial") |
Actor(Swift 5.5+) | 高层、零锁代码 | actor Counter { ... } |
NSLock 示例
swift
class SafeCounter {
private var value = 0
private let lock = NSLock()
func increment() {
lock.lock()
defer { lock.unlock() }
value += 1
}
func get() -> Int {
lock.lock()
defer { lock.unlock() }
return value
}
}
Actor 示例(推荐)
swift
actor CounterActor {
private var value = 0
func increment() { value += 1 }
func get() -> Int { value }
}
// 使用
let counter = CounterActor()
Task {
await counter.increment()
print(await counter.get())
}
真实世界场景演练
场景 | 并发模型 | 关键代码片段 |
---|---|---|
Web 服务器 | GCD + 并行队列 | DispatchQueue.global().async { handle(request) } |
图片滤镜 | concurrentPerform |
DispatchQueue.concurrentPerform(iterations: count) { applyFilter($0) } |
游戏引擎 | 多线程渲染 | 渲染线程 + 逻辑线程 + Actor 共享状态 |
思维导图:如何选择工具
arduino
需求: 线程安全
├─ 只读数据 → 无需同步
├─ 低频写 → NSLock / 串行 queue
├─ 高频写 → Actor (零锁、可组合)
└─ 复杂依赖 → Task + Actor + AsyncSequence
常见问题 FAQ
问题 | 回答 |
---|---|
何时用 Task vs DispatchQueue? | 新项目优先 Task ,老代码逐步迁移。 |
Actor 会降低性能吗? | 轻微调度开销,远低于锁竞争。 |
MainActor 是什么? | 系统预定义的全局 Actor,强制代码跑在主线程。 |
一句话总结
线程是地基,并发是设计思想,并行是多核福利;用 GCD/Task 管理线程,用 Actor/锁 保证安全,你的 Swift App 就能既快又稳。