
Swift 并发实战:async/await、Actor 与结构化并发
Swift 并发(从 Swift 5.5 引入,并在 Swift 6 中显著增强)提供了一种安全且富有表现力的模型来编写并发代码。回调金字塔和 DispatchQueue 的繁琐操作已成为过去。
基础:async/await

定义和调用异步函数
func fetchUser(id: String) async throws -> User {
let url = URL(string: "https://api.example.com/users/\(id)")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw APIError.invalidResponse
}
return try JSONDecoder().decode(User.self, from: data)
}
从同步代码桥接
override func viewDidLoad() {
super.viewDidLoad()
Task {
await loadProfile()
}
}
func fetchImageFromLegacyAPI(_ url: URL) async throws -> UIImage {
try await withCheckedThrowingContinuation { continuation in
legacyImageLoader.load(url: url) { result in
switch result {
case .success(let image): continuation.resume(returning: image)
case .failure(let error): continuation.resume(throwing: error)
}
}
}
}
Actor 模型:安全的共享状态
Actor 通过在编译时隔离可变状态来防止数据竞争。
actor UserCache {
private var cache: [String: User] = [:]
private var fetchTasks: [String: Task<User, Error>] = [:]
func user(for id: String) async throws -> User {
if let cached = cache[id] { return cached }
if let existingTask = fetchTasks[id] {
return try await existingTask.value
}
let task = Task<User, Error> {
try await APIClient.shared.fetchUser(id: id)
}
fetchTasks[id] = task
do {
let user = try await task.value
cache[id] = user
fetchTasks.removeValue(forKey: id)
return user
} catch {
fetchTasks.removeValue(forKey: id)
throw error
}
}
func invalidate(id: String) { cache.removeValue(forKey: id) }
}
@MainActor
@MainActor
class ProfileViewModel: ObservableObject {
@Published var user: User?
@Published var isLoading = false
@Published var error: Error?
private let userCache = UserCache()
func load(userId: String) async {
isLoading = true
defer { isLoading = false }
do {
user = try await userCache.user(for: userId)
} catch {
self.error = error
}
}
}

结构化并发
并发 async let
func fetchAllUserData(userId: String) async throws -> UserDashboard {
async let profile = APIClient.shared.fetchProfile(userId: userId)
async let posts = APIClient.shared.fetchPosts(userId: userId)
async let followers = APIClient.shared.fetchFollowers(userId: userId)
return try await UserDashboard(
profile: profile,
posts: posts,
followers: followers
)
}
动态工作的 TaskGroup
func downloadImages(urls: [URL]) async throws -> [URL: UIImage] {
try await withThrowingTaskGroup(of: (URL, UIImage).self) { group in
for url in urls {
group.addTask {
let image = try await ImageLoader.shared.load(url: url)
return (url, image)
}
}
var results: [URL: UIImage] = [:]
for try await (url, image) in group {
results[url] = image
}
return results
}
}
任务取消

协作式取消
func processLargeDataset(_ items: [DataItem]) async throws -> [ProcessedItem] {
var results: [ProcessedItem] = []
for (index, item) in items.enumerated() {
try Task.checkCancellation()
let processed = try await processItem(item)
results.append(processed)
if index % 100 == 0 {
await Task.yield()
}
}
return results
}
SwiftUI 中的可取消视图任务
struct SearchView: View {
@State private var query = ""
@State private var results: [SearchResult] = []
var body: some View {
VStack {
SearchBar(text: $query)
ResultsList(results: results)
}
.task(id: query) {
guard !query.isEmpty else { results = []; return }
do {
try await Task.sleep(for: .milliseconds(300))
results = try await SearchService.search(query: query)
} catch is CancellationError {
// 忽略取消
} catch {
print("搜索错误:", error)
}
}
}
}
AsyncSequence
func processEvents() async {
let stream = AsyncStream<WebSocketMessage> { continuation in
webSocket.onMessage = { message in
continuation.yield(message)
}
webSocket.onClose = {
continuation.finish()
}
}
for await message in stream {
await handleMessage(message)
}
}
Swift 6 严格并发检查
// Sendable 一致性
struct UserData: Sendable {
let id: String
let name: String
}
// @unchecked Sendable 用于手动安全保证
final class ThreadSafeCounter: @unchecked Sendable {
private var count = 0
private let lock = NSLock()
func increment() {
lock.withLock { count += 1 }
}
var value: Int { lock.withLock { count } }
}
性能模式
限制并发以避免系统过载:
func batchProcess<T>(items: [T], maxConcurrency: Int = 4) async throws {
try await withThrowingTaskGroup(of: Void.self) { group in
var inFlight = 0
for item in items {
if inFlight >= maxConcurrency {
try await group.next()
inFlight -= 1
}
group.addTask { try await processItem(item) }
inFlight += 1
}
try await group.waitForAll()
}
}
结论
Swift 并发改变了 iOS 和 macOS 开发。async/await 语法消除了回调金字塔,Actor 在编译时防止数据竞争,结构化并发使并行工作安全且可读。借助 Swift 6 的严格检查,编译器成为你的并发安全网,使代码更易于推理、更安全,并且通常更快。