Swift并发开发者Skill swift-concurrency-developer

这个技能专注于Swift并发编程,提供基于Office Building心智模型的专家指导,涵盖actors、isolation、Sendable、TaskGroups等关键概念,帮助开发者解决并发警告、数据竞争问题,优化代码性能。适用于移动开发、iOS应用开发等场景。关键词:Swift并发,actor模型,数据安全,移动开发,iOS开发,并发编程。

移动开发 0 次安装 0 次浏览 更新于 3/15/2026

name: swift-concurrency-developer description: 使用 Office Building 心智模型提供 Swift 并发编程的专家指导。适用于处理 actors、isolation、Sendable、TaskGroups,或修复并发警告和数据竞争问题。

Swift 并发开发者(智能路由器)

目的

使用来自 Fucking Approachable Swift Concurrency 的 “Office Building” 心智模型,结合 Swift Concurrency Course 的综合参考资料,提供 Swift 并发系统的专家指导。

自动激活时机

  • 处理 actors、isolation、Sendable、TaskGroups
  • 关键词:actorisolationSendableTaskGroupnonisolatedasync let
  • 修复并发警告或数据竞争问题

代理行为合约(遵循这些规则)

  1. 分析项目/包文件以找出 Swift 语言模式(Swift 5.x vs Swift 6)和使用的 Xcode/Swift 工具链,当建议依赖于此时。
  2. 在提出修复之前,识别隔离边界:@MainActor、自定义 actor、actor 实例隔离或 nonisolated。
  3. 不要推荐 @MainActor 作为通用修复。证明为什么主 actor 隔离适用于代码。
  4. 优先选择结构化并发(子任务、任务组)而非非结构化任务。仅在明确原因下使用 Task.detached
  5. 如果推荐 @preconcurrency@unchecked Sendablenonisolated(unsafe),要求:
    • 记录安全不变式
    • 后续工单以移除或迁移它
  6. 对于迁移工作,优化最小影响范围(小、可评审的更改)并添加验证步骤。
  7. 课程参考资料仅用于深入学习。仅在它们明显帮助回答开发者问题时使用。

项目设置发现

分析 Swift 项目的并发问题时:

  1. 项目设置发现

    • 使用 ReadPackage.swift 上获取 SwiftPM 设置(工具版本、严格并发标志、即将推出的功能)
    • 使用 Grep.pbxproj 文件中查找 SWIFT_STRICT_CONCURRENCYSWIFT_DEFAULT_ACTOR_ISOLATION
  2. 手动检查

    • SwiftPM:检查 Package.swift 中的 .enableExperimentalFeature("StrictConcurrency=targeted") 或类似内容
    • Xcode 项目:在 project.pbxproj 中搜索 SWIFT_DEFAULT_ACTOR_ISOLATIONSWIFT_STRICT_CONCURRENCY

核心心智模型:办公楼

将您的应用视为一座办公楼,其中 隔离域 是带锁的私人办公室:

概念 办公楼类比 Swift
MainActor 前台(处理所有 UI) @MainActor
actor 部门办公室(会计、法律) actor BankAccount { }
nonisolated 走廊(共享空间) nonisolated func name()
Sendable 复印件(安全分享) struct User: Sendable
Non-Sendable 原始文档(留在一个办公室) class Counter { }

关键洞见:您不能闯入他人的办公室。您敲门(await)并等待。

快速决策树

当开发者需要并发指导时:

  1. 从零开始异步代码?

    • 阅读 references/async-await-basics.md 获取基础模式
    • 对于并行操作 → references/tasks.md(async let、任务组)
  2. 保护共享可变状态?

    • 需要保护基于类的状态 → references/actors.md(actors、@MainActor)
    • 需要线程安全值传递 → references/sendable.md(Sendable 一致性)
  3. 管理异步操作?

    • 结构化异步工作 → references/tasks.md(Task、子任务、取消)
    • 流式数据 → references/async-sequences.md(AsyncSequence、AsyncStream)
  4. 处理遗留框架?

    • Core Data 集成 → references/core-data.md
    • 通用迁移 → references/migration.md
  5. 性能或调试问题?

    • 慢速异步代码 → references/performance.md(性能分析、暂停点)
    • 测试问题 → references/testing.md(XCTest、Swift Testing)
  6. 理解线程行为?

    • 阅读 references/threading.md 获取线程/任务关系和隔离
  7. 任务内存问题?

    • 阅读 references/memory-management.md 获取防循环引用模式

优先处理手册(常见错误 -> 下一步最佳操作)

  • SwiftLint 并发相关警告
    • 使用 references/linting.md 获取规则意图和首选修复;避免使用虚拟 awaits 作为 “修复”。
  • “发送非 Sendable 类型的值…可能引发数据竞争”
    • 首先:识别值跨隔离边界的位置
    • 然后:使用 references/sendable.mdreferences/threading.md
  • “主 actor 隔离…无法从非隔离上下文使用”
    • 首先:决定它是否真正属于 @MainActor
    • 然后:使用 references/actors.md(全局 actors、nonisolated、隔离参数)
  • XCTest 异步错误,如 “wait(…) 在异步上下文中不可用”
    • 使用 references/testing.mdawait fulfillment(of:) 和 Swift Testing 模式)
  • Core Data 并发警告/错误
    • 使用 references/core-data.md(DAO/NSManagedObjectID、默认隔离冲突)

快速模式

异步/等待

func fetchUser(id: Int) async throws -> User {
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

使用 async let 并行工作

async let avatar = fetchImage("avatar.jpg")
async let banner = fetchImage("banner.jpg")
return Profile(avatar: try await avatar, banner: try await banner)

任务

// SwiftUI - 当视图消失时取消
.task { avatar = await downloadAvatar() }

// 手动任务(继承 actor 上下文)
Task { await saveProfile() }

任务组用于动态并行工作

try await withThrowingTaskGroup(of: Void.self) { group in
    group.addTask { avatar = try await downloadAvatar() }
    group.addTask { bio = try await fetchBio() }
    try await group.waitForAll()
}

Actors

actor BankAccount {
    var balance: Double = 0
    func deposit(_ amount: Double) { balance += amount }

    // 不需要 await - 在 actor 内部可直接访问
    nonisolated func bankName() -> String { "Acme Bank" }
}

await account.deposit(100)  // 从外部必须 await
let name = account.bankName()  // 不需要 await

Sendable 类型

// 自动 Sendable - 值类型
struct User: Sendable {
    let id: Int
    let name: String
}

// 具有内部同步的线程安全类
final class ThreadSafeCache: @unchecked Sendable {
    private let lock = NSLock()
    private var storage: [String: Data] = [:]
}

常见错误

1. 认为异步 = 后台

// 错误:仍阻塞主线程!
@MainActor func slowFunction() async {
    let result = expensiveCalculation()  // 同步 = 阻塞
}

// 正确:使用分离任务处理 CPU 密集型工作
Task.detached(priority: .userInitiated) {
    let result = expensiveCalculation()
    await MainActor.run { updateUI(result) }
}

2. 创建过多 actors

大多数内容可以存在于 MainActor 上。仅当有无法在 MainActor 上的共享可变状态时才创建 actors。

3. 不必要地使用 MainActor.run

// 错误
await MainActor.run { self.data = data }

// 正确 - 注释函数
@MainActor func loadData() async { self.data = await fetchData() }

4. 阻塞协作线程池(违反运行时合约)

永远不要在异步代码中使用 DispatchSemaphoreDispatchGroup.wait() 或条件变量。

为什么:这些原语对运行时隐藏依赖。协作线程池有一个合约,即线程总是会向前推进。阻塞原语违反此合约并可能导致死锁。

// ❌ 危险:可能导致协作池死锁
let semaphore = DispatchSemaphore(value: 0)
Task {
    await doWork()
    semaphore.signal()
}
semaphore.wait()  // 线程阻塞,运行时不知情

// ✅ 使用 async/await 替代
let result = await doWork()

调试提示:设置 LIBDISPATCH_COOPERATIVE_POOL_STRICT=1 以在开发期间捕获阻塞调用。

5. 创建不必要的任务

// 错误 - 非结构化
Task { await fetchUsers() }
Task { await fetchPosts() }

// 正确 - 结构化并发
async let users = fetchUsers()
async let posts = fetchPosts()
await (users, posts)

6. 使所有内容都为 Sendable

并非所有内容都需要跨边界。询问数据是否真的在隔离域之间移动。

7. 不批处理 MainActor 跳转

主线程独立于协作线程池。每次跳转到/从 MainActor 都需要完整的上下文切换。

// ❌ 多次上下文切换
for item in items {
    let processed = await processItem(item)
    await MainActor.run { displayItem(processed) }  // 每次项目上下文切换
}

// ✅ 单次上下文切换
let processed = await processAllItems(items)
await MainActor.run {
    for item in processed { displayItem(item) }
}

快速参考

关键词 目的
async 函数可以暂停
await 在此暂停直到完成
Task { } 启动异步工作,继承上下文
Task.detached { } 启动异步工作,无上下文
@MainActor 在主线程上运行
actor 具有隔离可变状态的类型
nonisolated 退出 actor 隔离
Sendable 安全在隔离域之间传递
@unchecked Sendable 信任我,它是线程安全的
async let 启动并行工作
TaskGroup 动态并行工作

当编译器抱怨时

跟踪隔离:它从哪里来?代码试图在哪里运行?什么数据跨边界?

一旦问对问题,答案通常显而易见。

参考文件

根据需要加载这些文件以处理特定主题:

基础概念

  • async-await-basics.md - async/await 语法、执行顺序、async let、URLSession 模式
  • tasks.md - 任务生命周期、取消、优先级、任务组、结构化 vs 非结构化
  • threading.md - 线程/任务关系、暂停点、隔离域、nonisolated
  • glossary.md - 核心并发术语的快速定义

隔离与安全

  • actors.md - Actor 隔离、@MainActor、全局 actors、重入、自定义执行器、Mutex
  • sendable.md - Sendable 一致性、值/引用类型、@unchecked、区域隔离
  • memory-management.md - 任务中的循环引用、内存安全模式

高级模式

  • async-sequences.md - AsyncSequence、AsyncStream、何时使用 vs 常规异步方法
  • async-algorithms.md - Swift Async Algorithms 包、组合序列
  • task-local-values.md - 任务本地上下文传播、跟踪、日志模式
  • core-data.md - NSManagedObject sendability、自定义执行器、隔离冲突

质量与迁移

  • performance.md - 使用 Instruments 性能分析、减少暂停点、执行策略
  • testing.md - XCTest 异步模式、Swift Testing、并发测试工具
  • migration.md - Swift 6 迁移策略、闭包到异步转换、@preconcurrency
  • linting.md - 并发焦点 lint 规则和 SwiftLint async_without_await

项目特定参考(Anytype)

  • approachable-concurrency.md - 易用并发快速指南
  • swift-6-2-concurrency.md - Swift 6.2 并发更新(未来参考)
  • swiftui-concurrency-tour.md - SwiftUI 特定并发模式

最佳实践总结

  1. 优先选择结构化并发 - 尽可能使用任务组而非非结构化任务
  2. 最小化暂停点 - 保持 actor 隔离部分小以减少上下文切换
  3. 明智使用 @MainActor - 仅用于真正与 UI 相关的代码
  4. 使类型为 Sendable - 通过符合 Sendable 启用安全并发访问
  5. 处理取消 - 在长时间运行操作中检查 Task.isCancelled
  6. 避免阻塞 - 永远不要在异步上下文中使用信号量或锁(违反运行时合约)
  7. 测试并发代码 - 使用适当的异步测试方法并考虑时序问题
  8. 批处理 MainActor 跳转 - 分组 UI 更新以最小化跳转到/从主线程的上下文切换
  9. 理解运行时合约 - 线程必须总是向前推进;使用安全原语
  10. 使用 LIBDISPATCH_COOPERATIVE_POOL_STRICT=1 - 调试环境变量以捕获阻塞调用

验证清单(当更改并发代码时)

  • 在解释诊断之前,确认构建设置(默认隔离、严格并发、即将推出的功能)。
  • 重构后:
    • 运行测试,特别是并发敏感测试(见 references/testing.md)。
    • 如果与性能相关,使用 Instruments 验证(见 references/performance.md)。
    • 如果与生命周期相关,验证 deinit/取消行为(见 references/memory-management.md)。

进一步阅读

相关技能与文档

  • ios-dev-guidelinesIOS_DEVELOPMENT_GUIDE.md - 通用 Swift/iOS 模式、MVVM、协调器
  • tests-developer → 使用 Swift Testing 框架测试异步代码
  • swiftui-performance-developer → SwiftUI 视图中的性能优化

导航:此技能提供并发心智模型。对于通用 Swift/iOS 模式,见 ios-dev-guidelines

归属:Office Building 心智模型来自 Dimillian/Skills。参考文件来自 AvdLee/Swift-Concurrency-Agent-Skill