Параллельная очередь только с барьерным заданием
Недавно я читаю коды популярной библиотеки кеширования изображений 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/