Swift 并发的终局形态
Swift 从 5.5 引入 async/await 与 Actor,到 6.0 引入完整的数据隔离检查(Complete Concurrency Checking),再到 6.2 的一系列易用性改进,目标始终清晰:让数据竞争在编译期被消灭,而不是靠运行时排查。
Swift 6 语言模式下,跨 actor 传递非 Sendable 类型会直接编译报错。这曾让迁移痛苦,6.2 则大幅降低了心智负担。
一、async/await 与结构化并发
import Foundation
struct Repo: Decodable { let name: String; let stars: Int }
func fetchRepos(user: String) async throws -> [Repo] {
let url = URL(string: "https://api.github.com/users/\(user)/repos")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode([Repo].self, from: data)
}
// 结构化并发:任务组内的子任务生命周期受父任务约束
func loadDashboard() async throws -> (repos: [Repo], avatar: Data) {
try await withThrowingTaskGroup(of: Any?.self) { group in
group.addTask { try await fetchRepos(user: "apple") }
group.addTask { try await fetchAvatar(user: "apple") }
var repos: [Repo] = []
var avatar = Data()
for try await result in group {
if let r = result as? [Repo] { repos = r }
if let a = result as? Data { avatar = a }
}
return (repos, avatar)
}
}任务组保证:父任务取消时,所有子任务自动取消,不会出现泄漏的后台任务。
二、Actor 与 Sendable
// Actor 保证内部状态串行访问
actor Counter {
private var value = 0
func increment() -> Int {
value += 1
return value
}
}
// 跨 actor 传递必须 Sendable
struct User: Sendable {
let id: Int
let name: String
}
@MainActor
final class ViewModel: ObservableObject {
@Published var repos: [Repo] = []
func load() async {
// await 跨越 actor 边界,编译器强制插入挂起点
repos = (try? await fetchRepos(user: "apple")) ?? []
}
}Swift 6.2 的重要改进是 @concurrent 与默认的 nonisolated 行为调整:以前 nonisolated 异步函数会跳到后台执行器,导致大量意外的 actor 跳跃;6.2 起默认保持在调用方上下文,只有显式标注 @concurrent 才真正切到后台。
final class ImageLoader {
// 显式声明:这个耗时操作应该在后台并发执行
@concurrent
func decode(_ data: Data) async -> Image {
// CPU 密集解码
return Image(data: data)!
}
}三、服务端 Swift:Vapor 实战
// Package.swift 依赖
// .package(url: "https://github.com/vapor/vapor.git", from: "4.100.0")
import Vapor
func routes(_ app: Application) throws {
app.get("health") { _ in ["ok": true] }
app.post("users") { req async throws -> User in
let input = try req.content.decode(CreateUser.self)
guard input.email.contains("@") else {
throw Abort(.badRequest, reason: "邮箱格式不正确")
}
return try await UserStore.create(input)
}
// 流式响应
app.get("stream") { req -> Response in
let body = Response.Body(stream: { writer in
for i in 1...10 {
try await writer.write(.buffer(.init(string: "chunk \(i)\n")))
}
try await writer.write(.end)
})
return Response(status: .ok, body: body)
}
}Swift on Server 的优势在于:
- 内存占用远低于 JVM/Node,容器镜像可小到几十 MB;
- 强类型 + 编译期并发检查,线上崩溃率显著更低;
- 与 iOS 端共享模型层代码。
四、与 C/C++、Rust 互操作
// 直接调用 C 库,无需桥接文件之外的额外成本
import Foundation
func sha256(_ text: String) -> [UInt8] {
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
text.withCString { ptr in
CC_SHA256(UnsafeRawPointer(ptr), CC_LONG(strlen(ptr)), &hash)
}
return hash
}Swift 6 起对 C++ 互操作、以及通过 Swift 调用 Rust(借助 swift-bridge / uniffi 生成绑定)的支持明显增强,这让 Swift 在“渐进替换老代码”的场景中更实用。
五、迁移到 Swift 6 语言模式
// 逐模块开启,而不是一次性全量切换
// Package.swift
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
.enableExperimentalFeature("NonisolatedNonSendingByDefault"),
]步骤建议:
- 先把数据模型标注
Sendable; - 把全局可变状态收进 actor 或加
@MainActor; - 最后再打开 Swift 6 语言模式,逐个修复剩余警告。
小结
Swift 6.2 让严格并发从“处处报错”变得“默认合理”。编译期消灭数据竞争,是任何语言都值得追求的方向,而 Swift 目前走得最坚决。
评论 0
还没有评论,来说两句吧。