使用 DispatchGroup 时如何超时?

我们可以在 swift 中使用 DispatchGroup 将许多任务添加到组中。该小组将等到所有任务完成后再继续下一个代码。

let dg = DispatchGroup()
dg.notify(queue: .global()) {
   // run code here on completion
}

如果任务完成时间过长,有没有办法为此 dispatchGroup 添加超时?

[编辑]

我知道 DispatchGroup.wait(timeout:) 会增加超时。但这使它同步等待。有没有办法使用 notify 方法进行异步,但仍然有超时?

stack overflow How to have a timeout when using DispatchGroup?
原文答案
author avatar

接受的答案

如果您希望 DispatchGroup 异步超时,请尝试:

var dg: DispatchGroup? = DispatchGroup()
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
    self.dg = nil // after time out group is removed asynchronously
}
dg?.notify(queue: .global()) {
    // run code here on completion
}

答案:

作者头像

只是为了添加一种替代方式;要在代码的多个部分轻松重用它,您可以提供这样的 DispatchGroup 扩展:

extension DispatchGroup {
    func notify(queue: DispatchQueue, timeout: TimeInterval, execute work: @escaping () -> ()) {
        var selfDestructingCompletion: (() -> ())?
        selfDestructingCompletion = {
            selfDestructingCompletion = nil
            work()
        }
        self.notify(queue: queue) {
            selfDestructingCompletion?()
        }
        queue.asyncAfter(deadline: .now() + timeout) {
            selfDestructingCompletion?()
        }
    }
}

然后你会像这样使用:

// 1. something you need to have for the dispatch group anyway
let someSerialQueue = DispatchQueue(label: "someQueue")
let group = DispatchGroup()
for someApi in apiList {
    group.enter()
    someApi.call() {
        group.leave()
    }
}

// 2. the new method, just with the timeout parameter
group.notify(queue: someSerialQueue, timeout: 5.0) {
    // Run the completion for completing the tasks or for timeout in one place
}

这具有以下额外好处:

  • 只要你通过一个串行队列就没有线程问题(对于接受的答案不正确)
  • 使用时只在一处调用补全

如果您打算将其插入公共库,请务必将方法名称作为您的某个特定命名空间的前缀,以避免与此扩展的其他类似实现发生冲突。