Получить последний результат от DispatchGroup ожидания - PullRequest
0 голосов
/ 23 июня 2018

Описание проблемы:

Я хочу выполнить кучу асинхронных задач с помощью DispatchGroup, и когда все они закончили, он вернул результат. Кроме того, я хочу установить тайм-аут, ограничивающий процесс, и вернуть мне успешные результаты к тому времени. Я использовал следующую структуру:

Кодовый блок

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
}

Как получить последний результат, если истекло время ожидания?

1 Ответ

0 голосов
/ 23 июня 2018

Хорошо, значит, вы правильно используете функцию ввода / вывода DispatchGroup, но у вас возникают проблемы с доступом к их результатам.Я думаю, что вы ошибаетесь, пытаясь использовать как wait, так и notify, эти две функции предоставляют две разные функциональные возможности, которые обычно не используются вместе.После настройки ваших рабочих элементов, как вы сделали, у вас есть две опции:

  1. Подход wait

Эта функция блокирует очередь вызовов и ожидает синхронно либо для прошедшего времени в стене, либо для завершения всех рабочих элементов в группе.Поскольку он блокирует вызывающего, важно всегда иметь таймаут в этой функции.

Подход notify

Функция принимает целевую очередь и блок, который нужно запустить после завершения всех рабочих элементов в вашей группе.Здесь вы в основном просите систему уведомить вас, асинхронно , как только все рабочие элементы будут выполнены.Поскольку это асинхронный , мы обычно меньше беспокоимся о тайм-ауте, он ничего не блокирует.

Асинхронный wait (кажется, это то, что вы хотите?)

Если, как вам кажется, мы хотим получить уведомление, как только все рабочие элементы будут завершены, но также естьтайм-аут, мы должны сделать это сами, и это не так сложно.Мы можем добавить простое расширение для класса DispatchGroup ...

extension DispatchGroup {

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

}

Эта простая функция отправляет асинхронно в глобальную фоновую очередь, затем вызывает wait, которая будет ожидать завершения всех рабочих элементов, илиуказанное время ожидания, в зависимости от того, что наступит раньше.Затем он перезвонит вашему обработчику в указанной очереди.


Так что это теория, как вы можете использовать это.Мы можем сохранить ваши первоначальные настройки точно такими же

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

, а затем использовать нашу новую функцию, чтобы дождаться окончания

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
}
...