You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 6编译AsyncStack<>遇数据竞争风险错误:原因及修复

Swift 6下AsyncStack编译错误原因及修复方案

错误原因

Swift 6默认启用了严格并发检查,对跨并发上下文传递的值的安全性要求更高。当你在push方法中调用awaiter.resume(returning: newElement)时,newElement作为外部传入的参数,其所有权不由当前actor完全控制:

  • 若Element是可变引用类型,外部调用者可能在push执行期间同时修改该元素;
  • resume操作会将元素传递到另一个并发上下文(等待popOrWait的任务),这就存在数据竞争的风险,因此编译器触发了报错。

修复方案

方案1:约束Element遵循Sendable协议

给AsyncStack的泛型参数添加Sendable约束,确保存储和传递的元素是可安全跨并发上下文传递的类型(比如值类型、不可变引用类型、显式标记为Sendable的类型):

actor AsyncStack<Element: Sendable> {
  private var storage = [Element]()
  private var awaiters = [CheckedContinuation<Element,Error>]()
  
  public func push(_ newElement: Element) async -> Void {
    if !awaiters.isEmpty {
      let awaiter = awaiters.removeFirst()
      awaiter.resume(returning: newElement)
    } else {
      storage.insert(newElement, at: 0)
    }
  }
  
  public func popOrWait() async throws -> Element {
    if let element = storage.popLast() {
      return element
    }
    return try await withCheckedThrowingContinuation { continuation in
      awaiters.append(continuation)
    }
  }
}

方案2:显式复制元素(仅适用于值类型)

如果Element是值类型,显式复制元素可以让编译器确认传递的是独立副本,消除竞争风险:

// 在push方法中修改resume调用部分
if !awaiters.isEmpty {
  let awaiter = awaiters.removeFirst()
  var copiedElement = newElement // 利用值类型自动复制特性生成独立副本
  awaiter.resume(returning: copiedElement)
}

注意:此方案仅对值类型有效,引用类型仍需依赖Sendable约束保证安全性。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:12:16