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(典型的互斥锁用法),整个逻辑的核心是:
- 每次回调触发时,先尝试立即获取信号量;
- 如果拿到了(
.success),说明当前没有正在进行的UI处理,就把新的元数据任务派去主线程处理; - 如果拿不到(
.timedOut),说明上一次的UI处理还没完成,这次的元数据已经是“过期”的了——直接丢弃,不做任何处理,避免任务堆积; - 当主线程的UI处理完成后,调用
signal()把信号量计数加回1,让下一次的回调有机会获取信号量处理新数据。
总结一下
这种用法本质上是用信号量实现了**“任务节流”**:在高频触发的回调中,确保同一时间只有一个处理任务在执行,后续的过期任务直接丢弃,既保证了UI显示的是最新数据,又避免了线程阻塞和资源浪费。
内容的提问来源于stack exchange,提问作者Kalzem
相关产品推荐
相关产品推荐

