简体   繁体   English

如何停止DispatchGroup或OperationQueue等待?

[英]How to stop DispatchGroup or OperationQueue waiting?

DispatchGroup and OperationQueue have methods wait() and waitUntilAllOperationsAreFinished() which wait for all operations in respective queues to complete. DispatchGroupOperationQueue具有方法wait()waitUntilAllOperationsAreFinished() ,它们等待相应队列中的所有操作完成。

But even when I call cancelAllOperations it just changes the flag isCancelled in every running operation and stop the queue from executing new operations. 但是,即使我调用cancelAllOperations它也只是在每个正在运行的操作中更改了isCancelled标志,并停止了执行新操作的队列。 But it still waits for the operations to complete. 但是它仍然等待操作完成。 Therefore running the operations must be stopped from the inside. 因此,必须从内部停止运行操作。 But it is possible only if operation is incremental or has an inner cycle of any kind. 但是只有在操作是增量的或具有任何内部循环的情况下才有可能。 When it's just long external request (web request for example), there is no use of isCancelled variable. 当只是长时间的外部请求(例如Web请求)时,不使用isCancelled变量。

Is there any way of stopping the OperationQueue or DispatchGroup waiting for the operations to complete if one of the operations decides that all queue is now outdated? 如果其中一项操作确定所有队列现在都已过时,是否有任何方法可以停止OperationQueue或DispatchGroup等待操作完成?

The practical case is: mapping a request to a list of responders, and it is known that only one may answer. 实际情况是:将请求映射到响应者列表,并且已知只有一个人可以回答。 If it happens, queue should stop waiting for other operations to finish and unlock the thread. 如果发生这种情况,队列应停止等待其他操作完成并解锁线程。

Edit: DispatchGroup and OperationQueue usage is not obligatory, these are just tools I thought would fit. 编辑:DispatchGroup和OperationQueue的使用不是强制性的,这些只是我认为合适的工具。

OK, so I think I came up with something. 好,所以我想出了点什么。 Results are stable, I've just tested. 结果很稳定,我刚刚测试过。 The answer is just one semaphore :) 答案只是一个信号量:)

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)")
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM