Как семафор поддерживает порядок асинхронного цикла? - PullRequest
0 голосов
/ 01 декабря 2018

Я настроил этот скрипт для циклического прохождения через группу данных в фоновом режиме, и я успешно настроил семафор, чтобы держать все (массив, который будет заполнять таблицу) в порядке, но я не могу точно понять, как илипочему семафор держит массив в порядке.dispatchGroup вводится, цикл останавливается и ждет загрузки изображения, как только изображение получено, dispatchSemaphore устанавливается на 1, и сразу же dispatchGroup завершается, а семафор возвращается на 0,Семафор переключается так быстро от 0 до 1, что я не понимаю, как он поддерживает порядок в массиве.

let dispatchQueue = DispatchQueue(label: "someTask")
let dispatchGroup = DispatchGroup()
let dispatchSemaphore = DispatchSemaphore(value: 0)

dispatchQueue.async {

    for doc in snapshot.documents {

        // create data object for array

        dispatchGroup.enter()

        // get image with asynchronous completion handler
        Storage.storage().reference(forURL: imageId).getData(maxSize: 1048576, completion: { (data, error) in

            defer {
                dispatchSemaphore.signal()
                dispatchGroup.leave()
            }

            if let imageData = data,
                error == nil {
                // add image to data object
                // append to array
            }

        })

        dispatchSemaphore.wait()

    }

    // do some extra stuff in background after loop is done

}

dispatchGroup.notify(queue: dispatchQueue) {

    DispatchQueue.main.async {
        self.tableView.reloadData()
    }

}

Ответы [ 2 ]

0 голосов
/ 01 декабря 2018

Решение в вашем комментарии get image with asynchronous completion handler.Без семафора все загрузки изображений начнутся одновременно и начнут гонку за завершением, поэтому самое быстрое загружаемое изображение будет сначала добавлено в массив.

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

Использование последовательной очереди здесь не вариант, так как это приведет только к загрузке до start серийно, но вы не можете повлиять на порядок, в котором они заканчиваются.

Это довольно неэффективно, хотя.Ваш сетевой уровень, вероятно, может работать быстрее, если вы дадите ему несколько запросов одновременно (подумайте о параллельных загрузках и конвейерной передаче HTTP).Кроме того, вы «тратите» поток, который тем временем может выполнять какую-то другую работу.Если в это же время нужно проделать больше работы, GCD создаст другой поток, который тратит впустую память и другие ресурсы.

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

var images: [UIImage?] = Array(repeating: nil, count: snapshot.documents.count)

for (index, doc) in snapshot.documents.enumerated() {

    // create data object for array

    dispatchGroup.enter()

    // get image with asynchronous completion handler
    Storage.storage().reference(forURL: imageId).getData(maxSize: 1048576) { data, error in

        defer {
            dispatchGroup.leave()
        }

        if let imageData = data,
            error == nil {
            // add image to data object
            images[index] = image
        }
    }
}
0 голосов
/ 01 декабря 2018

DispatchGroup здесь на самом деле ничего не делает.У вас есть взаимное исключение, предоставляемое DispatchSemaphor, а упорядочение просто обеспечивается порядком итерации snapshot.documents

...