Swift 中的并发与多线程:高级技巧

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

并发与多线程在Swift中的高级应用

并发(concurrency)是iOS/macOS开发中最复杂和最重要的主题之一。在高级层面,Swift提供了强大的工具:从经典的Grand Central Dispatch(GCD)到现代的async/await模型和严格的Actor系统。本文将深入探讨如何高效管理线程、避免数据竞争以及编写线程安全代码。



1. Grand Central Dispatch (GCD):队列与组操作

GCD仍然是Swift多线程编程的基础。但在高级层面,不仅要理解main和global()的区别,更要掌握任务依赖管理。

创建自定义队列

let serialQueue = DispatchQueue(label: "com.pythonlib.serial")let concurrentQueue = DispatchQueue(label: "com.pythonlib.concurrent", attributes: .concurrent)

serialQueue.async { print("Task 1 in serial queue")}concurrentQueue.async { print("Task 2 in concurrent queue")}

DispatchGroup:多任务同步

let group = DispatchGroup()let queue = DispatchQueue.global()

queue.async(group: group) { sleep(1) print("Loading data 1")}queue.async(group: group) { sleep(2) print("Loading data 2")}

group.notify(queue: DispatchQueue.main) { print("All loads complete, updating UI")}

当需要等待多个并行操作完成时(例如图片加载或JSON解析),使用DispatchGroup。



2. 现代async/await模型与Task

从Swift 5.5开始,语言通过async和await关键字原生支持异步编程。这简化了代码可读性,避免了"闭包金字塔"。

声明与调用异步函数

func fetchUserData() async -> String {    // Simulating network request    try? await Task.sleep(nanoseconds: 2_000_000_000)    return "User data loaded"}

Task { let result = await fetchUserData() print(result) // Prints "User data loaded"}

使用async let并行调用

func loadImage() async -> Data { return Data() }func loadMetadata() async -> String { return "meta" }

Task { async let image = loadImage() async let metadata = loadMetadata() let result = try await (image, metadata) print("Image: \\(result.0), metadata: \\(result.1)")}

async let允许并行启动多个异步任务并等待所有任务完成。这比顺序调用更高效。



3. Actors:语言级别的线程安全

Actors是一种防止数据竞争的新机制。它们自动保证对其状态的访问是同步的。

定义与使用Actor

actor BankAccount {    private var balance: Double = 0.0        func deposit(amount: Double) {        balance += amount        print("Balance after deposit: \\(balance)")    }        func withdraw(amount: Double) -> Bool {        guard balance >= amount else { return false }        balance -= amount        return true    }        func getBalance() -> Double { balance }}

Task { let account = BankAccount() await account.deposit(amount: 100) let success = await account.withdraw(amount: 50) print("Withdrawal successful: \\(success)")}

所有Actor方法默认都是隔离的——只能通过await调用。这避免了多线程意外修改数据。

非隔离方法(nonisolated)

actor Logger {    nonisolated func log(message: String) {        print("Log: \\(message)")                

博客

书籍推荐