Понимание dispatch_async
У меня есть вопрос вокруг этого кода
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:
kLatestKivaLoansURL];
[self performSelectorOnMainThread:@selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
Первый параметр этого кода:
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
Мы просим этот код выполнять последовательные задачи в глобальной очереди, чье определение состоит в том, что оно возвращает глобальную параллельную очередь заданного уровня приоритета?
В чем преимущество использования dispatch_get_global_queue
в главной очереди?
Я смущен. Не могли бы вы помочь мне понять это лучше.
Ответы
Ответ 1
Основной причиной, по которой вы используете очередь по умолчанию в главной очереди, является запуск задач в фоновом режиме.
Например, если я загружаю файл из Интернета, и я хочу обновить пользователя о ходе загрузки, я запустил загрузку в очереди приоритетов по умолчанию и обновил бы интерфейс в основной очереди асинхронно.
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
});
});
Ответ 2
Все очереди DISPATCH_QUEUE_PRIORITY_X являются параллельными очередями (что означает, что они могут выполнять сразу несколько задач) и являются FIFO в том смысле, что задачи в заданной очереди начнут выполняться с использованием "первого в первом порядке". Это по сравнению с основной очередью (из dispatch_get_main_queue()), которая является последовательной очередью (задачи начнут выполнять и закончить выполнение в том порядке, в котором они получены).
Итак, если вы отправите 1000 dispatch_async() блоков в DISPATCH_QUEUE_PRIORITY_DEFAULT, эти задачи начнут выполняться в том порядке, в котором вы отправили их в очередь. Аналогично для очередей HIGH, LOW и BACKGROUND. Все, что вы отправляете в любую из этих очередей, выполняется в фоновом режиме на альтернативных потоках, вдали от основного потока приложений. Поэтому эти очереди подходят для выполнения таких задач, как загрузка фона, сжатие, вычисление и т.д.
Обратите внимание, что порядок выполнения - это FIFO для каждой очереди. Поэтому, если вы отправляете 1000 задач dispatch_async() в четыре разные параллельные очереди, равномерно распределяя их и отправляя их в BACKGROUND, LOW, DEFAULT и HIGH по порядку (т.е. планируете последние 250 задач в очереди HIGH), очень вероятно, что первые задачи, которые вы видите, запускаются в этой HIGH-очереди, поскольку система взяла на себя ответственность за то, что эти задачи должны как можно быстрее добраться до ЦП.
Отметьте также, что я говорю: "начнет действовать по порядку", но имейте в виду, что в качестве параллельных очередей вещи не обязательно будут выполняться FINISH в порядке, зависящем от продолжительности времени для каждой задачи.
В соответствии с Apple:
https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
Параллельная очередь отправки полезна, когда у вас есть несколько задач, которые могут выполняться параллельно. Одновременная очередь по-прежнему является очередью в том, что она отменяет задачи в порядке очередности, первого порядка; однако одновременная очередь может отменить дополнительные задачи до завершения любых предыдущих задач. Фактическое количество задач, выполняемых параллельной очередью в любой момент времени, является переменной и может динамически изменяться по мере изменения условий в приложении. Многие факторы влияют на количество задач, выполняемых параллельными очередями, включая количество доступных ядер, объем работы, выполняемой другими процессами, а также количество и приоритет задач в других очередях последовательной отправки.
В принципе, если вы отправляете эти 1000 блоков dispatch_async() в очередь DEFAULT, HIGH, LOW или BACKGROUND, все они будут запускаться в том порядке, в котором вы их отправляете. Однако более короткие задачи могут заканчиваться до более длинных. Причинами этого являются наличие доступных ядер процессора или если текущие задачи очереди выполняют вычислительно-неинтенсивную работу (что заставляет систему думать, что она может отправлять дополнительные задачи параллельно независимо от количества ядер).
Уровень concurrency полностью обрабатывается системой и основан на нагрузке системы и других внутренних факторах. Это красота Grand Central Dispatch (система dispatch_async()) - вы просто делаете свои рабочие единицы как кодовые блоки, устанавливаете для них приоритет (на основе выбранной очереди) и позволяете системе обрабатывать остальные.
Итак, чтобы ответить на ваш предыдущий вопрос: вы частично правы. Вы "запрашиваете этот код" для выполнения параллельных задач в глобальной параллельной очереди на указанном уровне приоритета. Код в блоке будет выполняться в фоновом режиме, и любой дополнительный (похожий) код будет выполняться потенциально параллельно в зависимости от системной оценки доступных ресурсов.
"Основная" очередь с другой стороны (из dispatch_get_main_queue()) является последовательной очередью (не параллельной). Задачи, отправленные в основную очередь, всегда выполняются по порядку и всегда будут заканчиваться по порядку. Эти задачи также будут выполняться в потоке пользовательского интерфейса, поэтому он подходит для обновления вашего пользовательского интерфейса с сообщениями о ходе выполнения, уведомлениями о завершении и т.д.
Ответ 3
Быстрая версия
Это версия Swift версии David Objective-C. Вы используете глобальную очередь для запуска объектов в фоновом режиме и в основной очереди для обновления пользовательского интерфейса.
Swift 3
DispatchQueue.global(qos: .background).async {
// Background Thread
DispatchQueue.main.async {
// Run UI Updates
}
}