Swift

并发

本文详细介绍了 Swift 中的并发编程,包括 async/await、异步序列、任务与任务组、Actor 模型以及 Sendable 类型。

Swift 内置的并发模型提供了一种结构化的方式来编写异步和并行代码。它通过 async/await 语法、结构化并发(Structured Concurrency)和 Actor 模型,让异步代码更易读、更安全。

定义和调用异步函数

使用 async 关键字定义异步函数。调用异步函数时,使用 await 关键字标记可能的暂停点。

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

func updateUI() async {
    do {
        let url = URL(string: "https://example.com/photo.jpg")!
        let image = try await fetchPhoto(url: url)
        // 更新 UI
    } catch {
        print("Failed to fetch photo: \(error)")
    }
}

异步序列 (Asynchronous Sequences)

AsyncSequence 协议允许你像遍历普通序列一样遍历异步产生的值。使用 for await 循环。

import Foundation

let url = URL(string: "https://example.com/large-data.csv")!
for try await line in url.lines {
    print(line)
}

任务和任务组 (Tasks and Task Groups)

任务 (Tasks)

Task 是并发执行的基本单位。你可以使用 Task 初始化器从同步上下文进入异步上下文。

Task {
    await updateUI()
}

任务组 (Task Groups)

使用 withTaskGroupwithThrowingTaskGroup 创建任务组,可以动态添加子任务并并发执行。

func printPhotoGallery() async {
    await withTaskGroup(of: UIImage?.self) { group in
        let photoNames = ["gallery1", "gallery2", "gallery3"]
        for name in photoNames {
            group.addTask {
                return await downloadPhoto(named: name)
            }
        }
        
        for await photo in group {
            if let photo = photo {
                // 处理每张照片
            }
        }
    }
}

Actors

Actor 是一种引用类型,用于保护可变状态,防止数据竞争。Actor 一次只允许一个任务访问其可变状态。

actor TemperatureLogger {
    var measurements: [Int] = []
    
    func log(_ measurement: Int) {
        measurements.append(measurement)
    }
    
    var max: Int {
        return measurements.max() ?? 0
    }
}

let logger = TemperatureLogger()
Task {
    await logger.log(25)
    print(await logger.max)
}

Sendable 类型

Sendable 协议用于标记可以在并发域之间安全传递的类型。

  • 值类型(如结构体、枚举)如果其成员也是 Sendable,则自动符合 Sendable
  • Actor 自动符合 Sendable
  • 只有在不可变且 final,或者内部实现了同步机制时,才能符合 Sendable
struct User: Sendable {
    var name: String
    var age: Int
}

Swift 6 引入了严格的并发检查,确保在编译时捕获潜在的数据竞争。

在 GitHub 上编辑

上次更新于