如何停止DispatchGroup或OperationQueue等待?

时间:2017-09-18 09:52:31

标签: swift grand-central-dispatch nsoperationqueue

DispatchGroupOperationQueue有方法wait()waitUntilAllOperationsAreFinished()等待相应队列中的所有操作完成。

但即使我调用cancelAllOperations,它只会在每个正在运行的操作中更改标志isCancelled,并阻止队列执行新操作。但它仍然在等待操作完成。因此必须从内部停止运行操作。但只有当操作是增量操作或具有任何类型的内循环时才有可能。如果只是长外部请求(例如Web请求),则不会使用isCancelled变量。

如果其中一个操作决定所有队列现在都已过时,有没有办法停止OperationQueue或DispatchGroup等待操作完成?

实际案例是:将请求映射到响应者列表,并且已知只有一个人可以回答。如果发生这种情况,队列应该停止等待其他操作完成并解锁线程。

编辑:DispatchGroup和OperationQueue的使用不是强制性的,这些只是我认为适合的工具。

1 个答案:

答案 0 :(得分:1)

好的,所以我想我想出了点什么。结果很稳定,我刚刚测试过。答案只是一个信号量:)

let semaphore = DispatchSemaphore(value: 0)
let group = DispatchGroup()
let queue = DispatchQueue(label: "map-reduce", qos: .userInitiated, attributes: .concurrent)
let stopAtFirst = true // false for all results to be appended into one array
let values: [U] = <some input values>
let mapper: (U) throws -> T? = <closure>
var result: [T?] = []
for value in values {
    queue.async(group: group) {
        do {
            let res = try mapper(value)
            // appending must always be thread-safe, otherwise you end up with race condition and unstable results
            DispatchQueue.global().sync {
                result.append(res)
            }
            if stopAtFirst && res != nil {
                semaphore.signal()
            }
        } catch let error {
            print("Could not map value \"\(value)\" to mapper \(mapper): \(error)")
        }
    }
}
group.notify(queue: queue) { // this must be declared exactly after submitting all tasks, otherwise notification fires instantly
    semaphore.signal()
}
if semaphore.wait(timeout: .init(secondsFromNow: 5)) == .timedOut {
    print("MapReduce timed out on values \(values)")
}