axiom-concurrency-profiling

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Concurrency Profiling — Instruments Workflows

并发性能分析 — Instruments 工作流

Profile and optimize Swift async/await code using Instruments.
使用Instruments分析并优化Swift async/await代码。

When to Use

适用场景

Use when:
  • UI stutters during async operations
  • Suspecting actor contention
  • Tasks queued but not executing
  • Main thread blocked during async work
  • Need to visualize task execution flow
Don't use when:
  • Issue is pure CPU performance (use Time Profiler)
  • Memory issues unrelated to concurrency (use Allocations)
  • Haven't confirmed concurrency is the bottleneck
适合使用的情况:
  • 异步操作期间UI出现卡顿
  • 怀疑存在actor竞争问题
  • 任务已排队但未执行
  • 异步工作期间主线程被阻塞
  • 需要可视化任务执行流程
不适合使用的情况:
  • 问题属于纯CPU性能问题(使用Time Profiler工具)
  • 与并发无关的内存问题(使用Allocations工具)
  • 尚未确认并发是性能瓶颈

Swift Concurrency Template

Swift Concurrency模板

What It Shows

展示内容

TrackInformation
Swift TasksTask lifetimes, parent-child relationships
Swift ActorsActor access, contention visualization
Thread StatesBlocked vs running vs suspended
追踪项信息说明
Swift Tasks任务生命周期、父子关系
Swift ActorsActor访问、竞争可视化
Thread States阻塞、运行、挂起状态

Statistics

统计数据

  • Running Tasks: Tasks currently executing
  • Alive Tasks: Tasks present at a point in time
  • Total Tasks: Cumulative count created
  • Running Tasks:当前正在执行的任务
  • Alive Tasks:某一时刻存在的任务
  • Total Tasks:累计创建的任务总数

Color Coding

颜色编码

  • Blue: Task executing
  • Red: Task waiting (contention)
  • Gray: Task suspended (awaiting)
  • 蓝色:任务正在执行
  • 红色:任务等待中(竞争状态)
  • 灰色:任务已挂起(等待await)

Workflow 1: Diagnose Main Thread Blocking

工作流1:排查主线程阻塞问题

Symptom: UI freezes, main thread timeline full
  1. Profile with Swift Concurrency template
  2. Look at main thread → "Swift Tasks" lane
  3. Find long blue bars (task executing on main)
  4. Check if work could be offloaded
Solution patterns:
swift
// ❌ Heavy work on MainActor
@MainActor
class ViewModel: ObservableObject {
    func process() {
        let result = heavyComputation()  // Blocks UI
        self.data = result
    }
}

// ✅ Offload heavy work
@MainActor
class ViewModel: ObservableObject {
    func process() async {
        let result = await Task.detached {
            heavyComputation()
        }.value
        self.data = result
    }
}
症状:UI冻结,主线程时间线被占满
  1. 使用Swift Concurrency模板进行性能分析
  2. 查看主线程 → "Swift Tasks" 通道
  3. 寻找较长的蓝色条(主线程上执行的任务)
  4. 检查该工作是否可以被卸载到其他线程
解决方案示例
swift
// ❌ 在MainActor上执行繁重工作
@MainActor
class ViewModel: ObservableObject {
    func process() {
        let result = heavyComputation()  // 阻塞UI
        self.data = result
    }
}

// ✅ 卸载繁重工作
@MainActor
class ViewModel: ObservableObject {
    func process() async {
        let result = await Task.detached {
            heavyComputation()
        }.value
        self.data = result
    }
}

Workflow 2: Find Actor Contention

工作流2:排查Actor竞争问题

Symptom: Tasks serializing unexpectedly, parallel work running sequentially
  1. Enable "Swift Actors" instrument
  2. Look for serialized access patterns
  3. Red = waiting, Blue = executing
  4. High red:blue ratio = contention problem
Solution patterns:
swift
// ❌ All work serialized through actor
actor DataProcessor {
    func process(_ data: Data) -> Result {
        heavyProcessing(data)  // All callers wait
    }
}

// ✅ Mark heavy work as nonisolated
actor DataProcessor {
    nonisolated func process(_ data: Data) -> Result {
        heavyProcessing(data)  // Runs in parallel
    }

    func storeResult(_ result: Result) {
        // Only actor state access serialized
    }
}
More fixes:
  • Split actor into multiple (domain separation)
  • Use Mutex for hot paths (faster than actor hop)
  • Reduce actor scope (fewer isolated properties)
症状:任务意外串行化,并行工作按顺序执行
  1. 启用"Swift Actors"工具
  2. 查找串行访问模式
  3. 红色=等待,蓝色=执行
  4. 红/蓝比例高=存在竞争问题
解决方案示例
swift
// ❌ 所有工作通过Actor串行执行
actor DataProcessor {
    func process(_ data: Data) -> Result {
        heavyProcessing(data)  // 所有调用者都需等待
    }
}

// ✅ 将繁重工作标记为nonisolated
actor DataProcessor {
    nonisolated func process(_ data: Data) -> Result {
        heavyProcessing(data)  // 并行执行
    }

    func storeResult(_ result: Result) {
        // 仅Actor状态访问会被串行化
    }
}
更多修复方案
  • 将单个Actor拆分为多个(按领域划分)
  • 在热点路径使用Mutex(比Actor切换更快)
  • 缩小Actor作用范围(减少隔离属性)

Workflow 3: Thread Pool Exhaustion

工作流3:排查线程池耗尽问题

Symptom: Tasks queued but not executing, gaps in task execution
Cause: Blocking calls exhaust cooperative pool
  1. Look for gaps in task execution across all threads
  2. Check for blocking primitives
  3. Replace with async equivalents
Common culprits:
swift
// ❌ Blocks cooperative thread
Task {
    semaphore.wait()  // NEVER do this
    // ...
    semaphore.signal()
}

// ❌ Synchronous file I/O in async context
Task {
    let data = Data(contentsOf: fileURL)  // Blocks
}

// ✅ Use async APIs
Task {
    let (data, _) = try await URLSession.shared.data(from: fileURL)
}
Debug flag:
SWIFT_CONCURRENCY_COOPERATIVE_THREAD_BOUNDS=1
Detects unsafe blocking in async context.
症状:任务已排队但未执行,任务执行存在间隙
原因:阻塞调用耗尽了协作线程池
  1. 查看所有线程的任务执行间隙
  2. 检查是否存在阻塞原语
  3. 替换为异步等效实现
常见问题代码
swift
// ❌ 阻塞协作线程
Task {
    semaphore.wait()  // 绝对不要这样做
    // ...
    semaphore.signal()
}

// ❌ 在异步上下文执行同步文件I/O
Task {
    let data = Data(contentsOf: fileURL)  // 阻塞线程
}

// ✅ 使用异步API
Task {
    let (data, _) = try await URLSession.shared.data(from: fileURL)
}
调试标志
SWIFT_CONCURRENCY_COOPERATIVE_THREAD_BOUNDS=1
用于检测异步上下文中的不安全阻塞操作。

Workflow 4: Priority Inversion

工作流4:排查优先级反转问题

Symptom: High-priority task waits for low-priority
  1. Inspect task priorities in Instruments
  2. Follow wait chains
  3. Ensure critical paths use appropriate priority
swift
// ✅ Explicit priority for critical work
Task(priority: .userInitiated) {
    await criticalUIUpdate()
}
症状:高优先级任务等待低优先级任务
  1. 在Instruments中检查任务优先级
  2. 追踪等待链
  3. 确保关键路径使用合适的优先级
swift
// ✅ 为关键工作设置明确优先级
Task(priority: .userInitiated) {
    await criticalUIUpdate()
}

Thread Pool Model

线程池模型

Swift uses a cooperative thread pool matching CPU core count:
AspectGCDSwift Concurrency
ThreadsGrows unboundedFixed to core count
BlockingCreates new threadsSuspends, frees thread
DependenciesHiddenRuntime-tracked
Context switchFull kernel switchLightweight continuation
Why blocking is catastrophic:
  • Each blocked thread holds memory + kernel structures
  • Limited threads means blocked = no progress
  • Pool exhaustion deadlocks the app
Swift使用协作线程池,其大小与CPU核心数匹配:
特性GCDSwift Concurrency
线程无限制增长固定为核心数
阻塞处理创建新线程挂起任务,释放线程
依赖关系隐藏运行时追踪
上下文切换完整内核切换轻量级续体切换
阻塞操作的严重影响
  • 每个阻塞线程会占用内存和内核结构
  • 线程数量有限,阻塞意味着无法推进工作
  • 线程池耗尽会导致应用死锁

Quick Checks (Before Profiling)

预检查(分析前)

Run these checks first:
  1. Is work actually async?
    • Look for suspension points (
      await
      )
    • Sync code in async function still blocks
  2. Holding locks across await?
    swift
    // ❌ Deadlock risk
    mutex.withLock {
        await something()  // Never!
    }
  3. Tasks in tight loops?
    swift
    // ❌ Overhead may exceed benefit
    for item in items {
        Task { process(item) }
    }
    
    // ✅ Structured concurrency
    await withTaskGroup(of: Void.self) { group in
        for item in items {
            group.addTask { process(item) }
        }
    }
  4. DispatchSemaphore in async context?
    • Always unsafe — use
      withCheckedContinuation
      instead
先执行以下检查:
  1. 工作是否真的是异步的?
    • 查找挂起点(
      await
    • 异步函数中的同步代码仍会阻塞线程
  2. 在await期间持有锁?
    swift
    // ❌ 存在死锁风险
    mutex.withLock {
        await something()  // 绝对不要这样做!
    }
  3. 在循环中创建大量任务?
    swift
    // ❌ 开销可能超过收益
    for item in items {
        Task { process(item) }
    }
    
    // ✅ 使用结构化并发
    await withTaskGroup(of: Void.self) { group in
        for item in items {
            group.addTask { process(item) }
        }
    }
  4. 在异步上下文使用DispatchSemaphore?
    • 绝对不安全 — 改用
      withCheckedContinuation

Common Issues Summary

常见问题汇总

IssueSymptom in InstrumentsFix
MainActor overloadLong blue bars on main
Task.detached
,
nonisolated
Actor contentionHigh red:blue ratioSplit actors, use
nonisolated
Thread exhaustionGaps in all threadsRemove blocking calls
Priority inversionHigh-pri waits for low-priCheck task priorities
Too many tasksTask creation overheadUse task groups
问题Instruments中的症状修复方案
MainActor过载主线程上存在长蓝色条
Task.detached
,
nonisolated
Actor竞争红/蓝比例高拆分Actor,使用
nonisolated
线程池耗尽所有线程存在执行间隙移除阻塞调用
优先级反转高优先级任务等待低优先级任务检查任务优先级
任务数量过多任务创建开销大使用任务组

Safe vs Unsafe Primitives

安全与不安全原语

Safe with cooperative pool:
  • await
    , actors, task groups
  • os_unfair_lock
    ,
    NSLock
    (short critical sections)
  • Mutex
    (iOS 18+)
Unsafe (violate forward progress):
  • DispatchSemaphore.wait()
  • pthread_cond_wait
  • Sync file/network I/O
  • Thread.sleep()
    in Task
适用于协作线程池的安全原语
  • await
    , actors, 任务组
  • os_unfair_lock
    ,
    NSLock
    (短临界区)
  • Mutex
    (iOS 18+)
不安全原语(违反向前推进原则)
  • DispatchSemaphore.wait()
  • pthread_cond_wait
  • 同步文件/网络I/O
  • 在Task中使用
    Thread.sleep()

Resources

参考资源

WWDC: 2022-110350, 2021-10254
Docs: /xcode/improving-app-responsiveness
Skills: axiom-swift-concurrency, axiom-performance-profiling, axiom-synchronization
WWDC:2022-110350, 2021-10254
文档:/xcode/improving-app-responsiveness
技能:axiom-swift-concurrency, axiom-performance-profiling, axiom-synchronization