# Swift 并发编程完全指南

## 1. 现代并发模型演进
```swift
// 传统GCD方式(已不推荐)
DispatchQueue.global().async {
    let data = fetchData()
    DispatchQueue.main.async {
        updateUI(with: data)
    }
}

// Swift 并发方式(推荐)
Task {
    let data = await fetchData()
    await MainActor.run {
        updateUI(with: data)
    }
}

2. 核心概念

2.1 async/await 基础

func loadImage(from url: URL) async throws -> UIImage {
    let (data, _) = try await URLSession.shared.data(from: url)
    guard let image = UIImage(data: data) else {
        throw ImageError.invalidData
    }
    return image
}

2.2 Task 系统

// 创建后台任务
let imageTask = Task.detached(priority: .high) {
    return try await loadImage(from: remoteURL)
}

// 取消任务
imageTask.cancel()

// 获取结果
do {
    let image = try await imageTask.value
} catch {
    handleError(error)
}

3. 结构化并发

3.1 TaskGroup 模式

func fetchAllUserData() async throws -> [UserData] {
    try await withThrowingTaskGroup(of: UserData.self) { group in
        for userId in userIds {
            group.addTask {
                try await fetchUserData(id: userId)
            }
        }
        
        var results = [UserData]()
        for try await data in group {
            results.append(data)
        }
        return results.sorted { $0.id < $1.id }
    }
}

3.2 async let 绑定

async let user = fetchUserProfile()
async let posts = fetchUserPosts()
async let friends = fetchUserFriends()

let profile = try await Profile(
    user: await user,
    posts: await posts,
    friends: await friends
)

4. 数据竞争防护

4.1 Actor 模型

actor BankAccount {
    private var balance: Decimal = 0.0
    
    func deposit(_ amount: Decimal) {
        balance += amount
    }
    
    func withdraw(_ amount: Decimal) throws {
        guard balance >= amount else {
            throw BankError.insufficientFunds
        }
        balance -= amount
    }
    
    func currentBalance() -> Decimal {
        balance
    }
}

// 使用示例
let account = BankAccount()
Task {
    await account.deposit(1000)
    try await account.withdraw(500)
    let balance = await account.currentBalance()
    print("Current balance: \(balance)")
}

4.2 Sendable 协议

struct User: Sendable {
    let id: UUID
    let name: String
}

class UnsafeClass: @unchecked Sendable {
    private var queue = DispatchQueue(label: "sync.queue")
    private var _count = 0
    
    var count: Int {
        queue.sync { _count }
    }
    
    func increment() {
        queue.async { self._count += 1 }
    }
}

5. 高级并发模式

5.1 AsyncSequence 处理流数据

func monitorFileChanges() async throws {
    let handle = try FileHandle(forReadingFrom: logFileURL)
    
    for try await line in handle.bytes.lines {
        if line.contains("ERROR") {
            await sendAlert(message: line)
        }
    }
}

5.2 AsyncStream 自定义异步序列

func locationUpdates() -> AsyncStream<CLLocation> {
    AsyncStream { continuation in
        let manager = CLLocationManager()
        manager.delegate = LocationDelegate(continuation: continuation)
        manager.startUpdatingLocation()
        
        continuation.onTermination = { @Sendable _ in
            manager.stopUpdatingLocation()
        }
    }
}

class LocationDelegate: NSObject, CLLocationManagerDelegate {
    let continuation: AsyncStream<CLLocation>.Continuation
    
    init(continuation: AsyncStream<CLLocation>.Continuation) {
        self.continuation = continuation
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        for location in locations {
            continuation.yield(location)
        }
    }
}

6. 性能优化技巧

6.1 任务优先级管理

Task(priority: .userInitiated) {
    // 高优先级任务
}

Task(priority: .utility) {
    // 后台任务
}

6.2 协作式取消检查

func processLargeDataset() async throws {
    try Task.checkCancellation()
    
    for item in dataset {
        // 每次迭代检查取消状态
        if Task.isCancelled { break }
        
        await processItem(item)
    }
}

7. 与现有技术集成

7.1 桥接 GCD 代码

func legacyOperation() async -> Result {
    await withCheckedContinuation { continuation in
        OldGCDClass.doSomethingAsync { result in
            continuation.resume(returning: result)
        }
    }
}

7.2 Combine 互操作

func fetchPublisher() -> AnyPublisher<Data, Error> {
    let task = Task {
        try await fetchData()
    }
    
    return Future { promise in
        Task {
            do {
                let result = try await task.value
                promise(.success(result))
            } catch {
                promise(.failure(error))
            }
        }
    }
    .eraseToAnyPublisher()
}

8. 调试与测试

8.1 运行时检测

@MainActor func updateUI() { /* ... */ }

Task {
    await updateUI() // 编译器保证主线程执行
}

8.2 单元测试示例

class AsyncTests: XCTestCase {
    func testFetchData() async throws {
        let mockService = MockDataService()
        let data = try await mockService.fetchData()
        XCTAssertFalse(data.isEmpty)
    }
    
    func testConcurrentAccess() async {
        let counter = CounterActor()
        await withTaskGroup(of: Void.self) { group in
            for _ in 0..<1000 {
                group.addTask { await counter.increment() }
            }
        }
        let count = await counter.value
        XCTAssertEqual(count, 1000)
    }
}

actor CounterActor {
    private(set) var value = 0
    
    func increment() {
        value += 1
    }
}

9. 实战案例

9.1 图片加载器

actor ImageLoader {
    private var cache = [URL: UIImage]()
    private var tasks = [URL: Task<UIImage, Error>]()
    
    func loadImage(from url: URL) async throws -> UIImage {
        if let cached = cache[url] {
            return cached
        }
        
        if let existingTask = tasks[url] {
            return try await existingTask.value
        }
        
        let task = Task<UIImage, Error> {
            defer { tasks[url] = nil }
            let image = try await downloadImage(from: url)
            cache[url] = image
            return image
        }
        
        tasks[url] = task
        return try await task.value
    }
    
    private func downloadImage(from url: URL) async throws -> UIImage {
        let (data, _) = try await URLSession.shared.data(from: url)
        guard let image = UIImage(data: data) else {
            throw ImageError.invalidData
        }
        return image
    }
}

9.2 网络请求限流

actor RequestLimiter {
    private var activeTasks = 0
    private let maxConcurrent: Int
    private var pendingContinuations = [CheckedContinuation<Void, Never>]()
    
    init(maxConcurrent: Int = 3) {
        self.maxConcurrent = maxConcurrent
    }
    
    func beginRequest() async {
        if activeTasks >= maxConcurrent {
            await withCheckedContinuation { continuation in
                pendingContinuations.append(continuation)
            }
        }
        activeTasks += 1
    }
    
    func endRequest() {
        activeTasks -= 1
        if !pendingContinuations.isEmpty {
            let continuation = pendingContinuations.removeFirst()
            continuation.resume()
        }
    }
}

// 使用示例
let limiter = RequestLimiter()

func makeLimitedRequest() async throws -> Data {
    await limiter.beginRequest()
    defer { limiter.endRequest() }
    
    return try await URLSession.shared.data(from: url).0
}

10. 资源推荐

  1. 官方文档:

  2. WWDC推荐:

    • “Meet async/await in Swift” (WWDC21)
    • “Swift concurrency: Behind the scenes” (WWDC21)
    • “Visualize and optimize Swift concurrency” (WWDC22)
  3. 工具链:

    • Xcode 13+ 并发调试工具
    • Instruments 的 Swift Concurrency 模板
    • -Xfrontend -validate-tbd-against-ir=none 编译选项(解决复杂项目问题)
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐