简体   繁体   中英

Get the latest result from DispatchGroup wait

Problem Desctiption:

I want to do a bunch of asynchronous tasks by 'DispatchGroup' and when all of them finished it returned the result. In addition, I want to set timeout that limits the process and send me back the successful results by that time. I used the following structure:

Code Block

let myGroup = DispatchGroup()

var result = [Data]()
for i in 0 ..< 5 {
    myGroup.enter()

    Alamofire.request("https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
        print("Finished request \(i)")
        result.append(response.data)
        myGroup.leave()
    }
}

// Timeout for 10 seconds
myGroup.wait(timeout: DispatchTime(uptimeNanoseconds: 10000000000))

myGroup.notify(queue: .main) {
    return result
}

How can I get the latest result if timeout happened?

Ok, so you are correctly using the enter/leave functionality of the DispatchGroup , but are having trouble with how to access the results of these. I think you are going wrong by trying to use both wait and notify , these two functions provide two different pieces of functionality not usually used together. After having setup up your work items, as you have done, you have two options:

  1. The wait approach

This function blocks the calling queue and wait synchronously for either, the passed in wall time to elapse, or all work items in the group to leave. Because it is blocking the caller, it is important to always have a timeout in this function.

  1. The notify approach

The function takes a target queue, and a block to be run when all work items in your group have completed. Here you are basically asking the system to notify you, asynchronously once all work items have been completed. Since this is asynchronous we are usually less worried about the timeout, it's not blocking anything.

  1. Asynchronous wait (this appears to be what you want?)

If, as it seems you do, we want to be notified once all work items are complete, but also have a timeout, we have to do this ourselves, and it's not all that tricky. We can add a simple extension for the DispatchGroup class...

extension DispatchGroup {

    func notifyWait(target: DispatchQueue, timeout: DispatchTime, handler: @escaping (() -> Void)) {
        DispatchQueue.global(qos: .default).async {
            _ = self.wait(timeout: timeout)
            target.async {
                handler()
            }
        }
    }

}

This simple function dispatches asynchronously on a global background queue, then calls wait, which will wait for all work items to complete, or the specified timeout, whichever comes first. Then it will call back to your handler on the specified queue.


So that's the theory, how can you use this. We can keep your initial setup exactly the same

let myGroup = DispatchGroup()

var result = [Data]()
for i in 0 ..< 5 {
    myGroup.enter()

    Alamofire.request("https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
        print("Finished request \(i)")
        result.append(response.data)
        myGroup.leave()
    }
}

and then use our new function to wait for the end

myGroup.notifyWait(target: .main,
                   timeout: DispatchTime.now() + 10) {
    // here you can access the `results` list, with any data that has
    // been appended by the work items above before the timeout
    // was reached
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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