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

Swift 6中如何用Task替代DispatchSemaphore.wait(timeout:)实现事件检测?

基于Task替代DispatchSemaphore实现超时事件检测的方案

需求回顾

检测10秒时间窗口内是否有回调事件触发:

  • 事件可多次触发,只需判断是否发生过一次
  • 事件触发时需提前终止等待并返回true
  • 超时未触发则返回false

原代码问题

原使用DispatchSemaphore的实现在转为async函数后,Swift 6会抛出错误:

Instance method 'wait' is unavailable from asynchronous contexts; Await a Task handle instead; this is an error in Swift 6

这是因为semaphore.wait()会阻塞线程,违背了async/await的非阻塞设计原则,因此Swift 6明确禁止这种用法。

推荐的Swift 6实现方案

使用withCheckedContinuation结合Task取消机制,实现非阻塞的超时检测,同时支持提前终止:

func checkForEvents() async -> Bool {
    await withCheckedContinuation { continuation in
        // 保存事件回调引用,用于后续清理
        var eventHandler: ((Event) -> Void)?
        
        // 启动超时任务:10秒后返回false
        let timeoutTask = Task {
            try? await Task.sleep(nanoseconds: 10_000_000_000)
            continuation.resume(returning: false)
            eventService.onEvent = nil
        }
        
        // 绑定事件回调:触发后立即返回true并取消超时任务
        eventHandler = { _ in
            continuation.resume(returning: true)
            timeoutTask.cancel()
            eventService.onEvent = nil
        }
        eventService.onEvent = eventHandler
        
        // 处理外部取消场景:清理资源
        continuation.onCancel = {
            timeoutTask.cancel()
            eventService.onEvent = nil
        }
    }
}

实现关键点

  • 非阻塞等待:通过withCheckedContinuation将回调式事件转为async/await兼容的异步逻辑,不会阻塞线程
  • 提前终止:事件触发时立即调用continuation.resume()返回结果,并取消超时Task避免无效等待
  • 资源清理:无论是事件触发、超时还是外部取消,都会重置eventService.onEvent并取消超时Task,避免内存泄漏和回调残留
  • 线程安全:如果eventService.onEvent在多线程环境下被调用,可根据实际情况添加同步机制(比如用Atomic变量或串行队列)

对原替代方案的改进

你之前的Task.sleep方案无法提前终止的核心问题是没有监听事件触发并取消等待,上述方案通过绑定事件回调+Task取消完美解决了这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 06:50:26