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

Semaphore.wait(timeout: .now()) 的作用是什么?结合苹果代码解析

解析Semaphore.wait(timeout: .now())在AVCaptureMetadataOutput回调中的作用

刚好之前做扫码功能时研究过这个逻辑,我来给你拆解清楚~

先搞懂wait(timeout: .now())本身的作用

DispatchSemaphore的wait(timeout:)方法是用来尝试获取信号量的,当你传入.now()作为超时时间时,它会立即判断是否能拿到信号量,完全不会阻塞当前线程:

  • 如果信号量的当前计数大于0,就会把计数减1,返回.success——说明你成功“抢占”了这个信号量的使用权;
  • 如果信号量计数已经是0(意味着有其他任务正在占用),就直接返回.timedOut——连等都不等,直接放弃。

结合苹果的代码场景看具体用法

先看这个回调的背景:metadataOutput(_:didOutput:from:)是AVCapture识别到元数据(比如二维码、人脸)时触发的回调,这个回调会非常高频——摄像头每采集一帧符合条件的画面,就会触发一次。如果回调里的UI更新操作(比如画识别框)比较耗时,很容易出现「上一次的处理还没做完,新的回调又堆过来」的情况,最后导致UI显示的都是过期的识别结果,还会拖慢线程性能。

苹果这段代码里的逻辑就是用来解决这个问题:

func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
    // wait() 用于在旧通知仍在处理时丢弃新通知,避免堆积大量过期数据。
    if metadataObjectsOverlayLayersDrawingSemaphore.wait(timeout: .now()) == .success {
        DispatchQueue.main.async {
            // 一些处理操作...比如更新识别框UI
            self.metadataObjectsOverlayLayersDrawingSemaphore.signal()
        }
    }
}

这里的信号量metadataObjectsOverlayLayersDrawingSemaphore初始值应该是1(典型的互斥锁用法),整个逻辑的核心是:

  1. 每次回调触发时,先尝试立即获取信号量;
  2. 如果拿到了(.success),说明当前没有正在进行的UI处理,就把新的元数据任务派去主线程处理;
  3. 如果拿不到(.timedOut),说明上一次的UI处理还没完成,这次的元数据已经是“过期”的了——直接丢弃,不做任何处理,避免任务堆积;
  4. 当主线程的UI处理完成后,调用signal()把信号量计数加回1,让下一次的回调有机会获取信号量处理新数据。

总结一下

这种用法本质上是用信号量实现了**“任务节流”**:在高频触发的回调中,确保同一时间只有一个处理任务在执行,后续的过期任务直接丢弃,既保证了UI显示的是最新数据,又避免了线程阻塞和资源浪费。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:16:42