Swift 并发全景指南:Thread、Concurrency、Parallelism 一次搞懂

360 阅读3分钟

从底层线程到高层 Swift Concurrency,用代码带你吃透所有概念

为什么要关心这些概念?

  • 响应式 UI:主线程阻塞 = 卡死界面。
  • 高性能:多核 CPU 不并行 = 浪费算力。
  • 正确性:数据竞争 = 闪退或脏数据。

Thread:程序的最小执行单元

什么是 Thread

一条独立的执行路径,拥有独立的 栈 和 程序计数器,但与其他线程共享进程的内存空间。

手动创建 Thread(仅教学用,生产请用 GCD/Task)

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 核
目的提高响应能力提高吞吐量

并发示例(单核交替)

let queue = DispatchQueue(label: "concurrent", attributes: .concurrent)
queue.async { print("🍎 Task A") }
queue.async { print("🍏 Task B") }

单核 CPU 通过时间片轮转交替打印 A/B。

并行示例(多核同时)

DispatchQueue.concurrentPerform(iterations: 4) { i in
    print("🔥 Parallel \(i) on \(Thread.current)")
}

4 核机器会真正同时跑 4 条线程。

Swift 中的线程种类

线程用途注意
Main ThreadUI 更新 & 用户交互禁止长时间阻塞
Global Queue默认后台线程池QoS 分级(utility、background …)

主线程 & 后台线程实战

// 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:别让数据“赛车”

问题示例:数据竞争

class UnsafeCounter {
    var value = 0
    func increment() { value += 1 }
}

在多线程环境下 value += 1 可能丢失更新(读-改-写非原子)。

解决方案速查表

技术适用场景示例
NSLock低层临界区见下方代码
串行 DispatchQueue顺序执行任务DispatchQueue(label: "serial")
Actor(Swift 5.5+)高层、零锁代码actor Counter { ... }

NSLock 示例

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 示例(推荐)

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) }
图片滤镜concurrentPerformDispatchQueue.concurrentPerform(iterations: count) { applyFilter($0) }
游戏引擎多线程渲染渲染线程 + 逻辑线程 + Actor 共享状态

思维导图:如何选择工具

需求: 线程安全
├─ 只读数据 → 无需同步
├─ 低频写   → NSLock / 串行 queue
├─ 高频写   → Actor (零锁、可组合)
└─ 复杂依赖 → Task + Actor + AsyncSequence

常见问题 FAQ

问题回答
何时用 Task vs DispatchQueue?新项目优先 Task,老代码逐步迁移。
Actor 会降低性能吗?轻微调度开销,远低于锁竞争。
MainActor 是什么?系统预定义的全局 Actor,强制代码跑在主线程。

一句话总结

线程是地基,并发是设计思想,并行是多核福利;用 GCD/Task 管理线程,用 Actor/锁 保证安全,你的 Swift App 就能既快又稳。