Параллельная очередь только с барьерным заданием

Недавно я читаю коды популярной библиотеки кеширования изображений Kingfisher.

Я путаю насчет использования GCD на ImageDownloader, В этом загрузчике все ImageFetchLoad (задача извлечения изображения) связанные операции отправляются в параллельную очередь с именем barrierQueue:

barrierQueue = DispatchQueue(label: "com.onevcat.Kingfisher.ImageDownloader.Barrier.\(name)", attributes: .concurrent)

Непонятная часть - ВСЕ операции отправляются с использованием барьерной синхронизации:

barrierQueue.sync(flags: .barrier) {
    if let URL = task.internalTask.originalRequest?.url, let imageFetchLoad = self.fetchLoads[URL] {
        imageFetchLoad.downloadTaskCount -= 1
        if imageFetchLoad.downloadTaskCount == 0 {
            task.internalTask.cancel()
        }
    }
}

Каждая барьерная операция блокирует друг друга, что делает очередь фактически последовательной. Таким образом, почему Зимородок использует concurrent очередь вместо serial один?

1 ответ

Решение

В некоторых случаях имеет смысл использовать concurrent очередь за serial очередь для безопасности потока GCD. Последовательное выполнение может быть нежелательным или необходимым для всех операций в классе. Например, для операций "чтения", которые не изменяют состояние, имеет смысл выполнять их одновременно и синхронно. т. е. если операция "чтение" возвращает информацию, которая не зависит от состояния, которое может быть изменено другими операциями, которые вы ожидаете, нет причин ждать последовательного выполнения.

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

Я не могу говорить с конкретным обоснованием использования Kingfisher concurrent очереди, но просто хотел отметить пример использования, когда вы можете предпочесть concurrent над serial для безопасности очереди GCD. С помощью concurrent может обеспечить дополнительную гибкость, поскольку вы можете решить, следует ли выполнять операции одновременно или "последовательно" с флагом.barrier, в зависимости от поведения.

Для описания этого шаблона, посмотрите на .barrier описание здесь: http://khanlou.com/2016/04/the-GCD-handbook/

Другие вопросы по тегам