Swift并发编程Skill swift-concurrency

本技能提供Swift并发编程的专家指导,涵盖async/await、actors、tasks、Sendable和Swift 6迁移。帮助开发者编写安全、高性能的并发代码,解决数据竞争、线程安全、代码重构等问题。关键词:Swift并发,async/await,Actor隔离,Sendable,Swift 6迁移,数据竞争,线程安全,结构化并发,性能优化。

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

名称: swift-concurrency 描述: ‘关于Swift并发编程最佳实践、模式和实现的专家指导。当开发者提到以下内容时使用:(1) Swift并发、async/await、actors或tasks,(2) “使用Swift并发"或"现代并发模式”,(3) 迁移到Swift 6,(4) 数据竞争或线程安全问题,(5) 将闭包重构为async/await,(6) @MainActor、Sendable或actor隔离,(7) 并发代码架构或性能优化。’

Swift并发编程

概述

本技能提供关于Swift并发编程的专家指导,涵盖现代async/await模式、actors、tasks、Sendable一致性以及迁移到Swift 6。使用本技能帮助开发者编写安全、高性能的并发代码,并驾驭Swift结构化并发模型的复杂性。

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

  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. 课程参考仅用于深入学习。仅在它们明显有助于回答开发者问题时才使用。

项目设置评估(在建议前评估)

并发行为取决于构建设置。始终尝试确定:

  • 默认actor隔离(模块默认是@MainActor还是nonisolated?)
  • 严格并发检查级别(minimal/targeted/complete)
  • 是否启用了即将推出的功能(特别是NonisolatedNonsendingByDefault
  • Swift语言模式(Swift 5.x vs Swift 6)和SwiftPM工具版本

手动检查(无脚本)

  • SwiftPM:
    • 检查Package.swift中的.defaultIsolation(MainActor.self)
    • 检查Package.swift中的.enableUpcomingFeature("NonisolatedNonsendingByDefault")
    • 检查严格并发标志:.enableExperimentalFeature("StrictConcurrency=targeted")(或类似)。
    • 检查顶部的工具版本:// swift-tools-version: ...
  • Xcode项目:
    • project.pbxproj中搜索:
      • SWIFT_DEFAULT_ACTOR_ISOLATION
      • SWIFT_STRICT_CONCURRENCY
      • SWIFT_UPCOMING_FEATURE_(和/或SWIFT_ENABLE_EXPERIMENTAL_FEATURES

如果其中任何一项未知,请在给出与迁移相关的指导前请开发者确认。

快速决策树

当开发者需要并发指导时,遵循此决策树:

  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了解防止循环引用

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

  • “发送非Sendable类型的值…可能导致数据竞争”
    • 首先:识别值在哪里跨越了隔离边界
    • 然后:使用references/sendable.mdreferences/threading.md(特别是Swift 6.2行为变化)
  • “主actor隔离的…不能在非隔离上下文中使用”
    • 首先:决定它是否真正属于@MainActor
    • 然后:使用references/actors.md(全局actors、nonisolated、隔离参数)和references/threading.md(默认隔离)
  • “类属性’current’在异步上下文中不可用”(Thread API)
    • 使用references/threading.md避免基于线程的调试,依赖隔离+Instruments
  • XCTest异步错误,如"wait(…)在异步上下文中不可用"
    • 使用references/testing.mdawait fulfillment(of:)和Swift Testing模式)
  • Core Data并发警告/错误
    • 使用references/core-data.md(DAO/NSManagedObjectID、默认隔离冲突)

核心模式参考

何时使用每种并发工具

async/await - 使现有同步代码异步化

// 适用于:单个异步操作
func fetchUser() async throws -> User {
    try await networkClient.get("/user")
}

async let - 并行运行多个独立的异步操作

// 适用于:编译时已知的固定数量的并行操作
async let user = fetchUser()
async let posts = fetchPosts()
let profile = try await (user, posts)

Task - 启动非结构化异步工作

// 适用于:即发即弃操作,桥接同步到异步上下文
Task {
    await updateUI()
}

Task Group - 具有结构化并发的动态并行操作

// 适用于:编译时未知数量的并行操作
await withTaskGroup(of: Result.self) { group in
    for item in items {
        group.addTask { await process(item) }
    }
}

Actor - 保护可变状态免受数据竞争

// 适用于:从多个上下文访问的共享可变状态
actor DataCache {
    private var cache: [String: Data] = [:]
    func get(_ key: String) -> Data? { cache[key] }
}

@MainActor - 确保UI更新在主线程上

// 适用于:视图模型、UI相关类
@MainActor
class ViewModel: ObservableObject {
    @Published var data: String = ""
}

常见场景

场景:带UI更新的网络请求

Task { @concurrent in
    let data = try await fetchData() // 后台
    await MainActor.run {
        self.updateUI(with: data) // 主线程
    }
}

场景:多个并行网络请求

async let users = fetchUsers()
async let posts = fetchPosts()
async let comments = fetchComments()
let (u, p, c) = try await (users, posts, comments)

场景:并行处理数组项

await withTaskGroup(of: ProcessedItem.self) { group in
    for item in items {
        group.addTask { await process(item) }
    }
    for await result in group {
        results.append(result)
    }
}

Swift 6迁移快速指南

Swift 6的关键变化:

  • 严格并发检查默认启用
  • 编译时完全数据竞争安全
  • 在边界上强制执行Sendable要求
  • 所有异步边界的隔离检查

详细迁移步骤,请参阅references/migration.md

参考文件

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

  • async-await-basics.md - async/await语法、执行顺序、async let、URLSession模式
  • tasks.md - 任务生命周期、取消、优先级、任务组、结构化与非结构化
  • threading.md - 线程/任务关系、挂起点、隔离域、nonisolated
  • memory-management.md - 任务中的循环引用、内存安全模式
  • actors.md - Actor隔离、@MainActor、全局actors、可重入性、自定义执行器、Mutex
  • sendable.md - Sendable一致性、值/引用类型、@unchecked、区域隔离
  • async-sequences.md - AsyncSequence、AsyncStream、何时使用vs常规异步方法
  • core-data.md - NSManagedObject可发送性、自定义执行器、隔离冲突
  • performance.md - 使用Instruments进行性能分析、减少挂起点、执行策略
  • testing.md - XCTest异步模式、Swift Testing、并发测试工具
  • migration.md - Swift 6迁移策略、闭包到异步转换、@preconcurrency、FRP迁移

最佳实践总结

  1. 优先使用结构化并发 - 尽可能使用任务组而非非结构化任务
  2. 最小化挂起点 - 保持actor隔离部分小以减少上下文切换
  3. 明智使用@MainActor - 仅用于真正与UI相关的代码
  4. 使类型Sendable - 通过符合Sendable实现安全并发访问
  5. 处理取消 - 在长时间运行的操作中检查Task.isCancelled
  6. 避免阻塞 - 绝不在异步上下文中使用信号量或锁
  7. 测试并发代码 - 使用适当的异步测试方法并考虑时序问题

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

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

术语表

有关本技能中使用的核心并发术语的快速定义,请参阅references/glossary.md


注意:本技能基于Antoine van der Lee的全面Swift并发课程