Является DispatchQueue.global(qos:.userInteractive).async таким же, как DispatchQueue.main.async

Я прошел учебник: https://www.raywenderlich.com/148513/grand-central-dispatch-tutorial-swift-3-part-1

И натолкнулся на определение класса QoS User-interactive. Здесь упоминается, что это должно выполняться по основной теме. Итак, мой вопрос заключается в том, в чем разница между

DispatchQueue.global(qos: .userInteractive).async{} 

а также

DispatchQueue.main.async{}

Спасибо!!

Ответ 1

Определения "качество обслуживания" описаны здесь:

https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html

Похоже, что "основной" поток будет иметь класс QoS "User-interactive". Однако только потому, что поток создается с помощью QoS "User-interactive", не означает, что это "основной" поток.

Вы можете наблюдать это в отладчике Xcode. Поместите контрольную точку внутри блока асинхронизации и посмотрите панель активных потоков Debug Navigator. Когда DispatchQueue.global(qos:.userInteractive).async{} вызывается из основного потока, он отображается с другим именем, чем основной поток.

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

Также обратите внимание, что при использовании Xcode 9 с iOS 11 будет выдано предупреждение, когда к объекту пользовательского интерфейса будет обращен доступ из не основного потока.

Ответ 2

Любой, кто говорит, что глобальная очередь .userInitiated является основным потоком, просто неверна. Это очень приоритетная фоновая очередь, но это фоновая очередь (и она параллельна, в отличие от основного потока).

Собственный образец кода и комментарии Apple делают этот вопрос совершенно ясным:

// This handler gets called on the main thread; dispatch to a background queue for processing.
DispatchQueue.global(qos: .userInitiated).async {

Это лишний раз доказывает, что Apple полагает, что глобальная очередь .userInitiated - это "фоновая очередь", а не "основной поток".

Ответ 3

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

Допустимо иметь несколько очередей на уровне userInteractive. Это необходимо, если вам необходимо использовать несколько ядер одновременно для выполнения вычислений, необходимых для поддержания плавного взаимодействия с пользователем (обычно это своего рода анимация). Это очень редко необходимо, и это нужно делать с осторожностью, но если вам нужно вычислить что-то в основном потоке, а также вычислить что-то на другом ядре, чтобы не отставать от действий пользователя, для чего он нужен.

Но может быть только одна главная очередь. Это бывает userInteractive, но это не его точка. Большая часть UIKit не является потокобезопасной, и она действительна только для доступа к этим классам в основной очереди, а не только для любой пользовательской очереди.

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

Ответ 4

Вы можете использовать DispatchQueue.global(qos:.userInteractive).async{} если вы хотите сделать что-то очень быстрое в фоновом режиме, когда пользователь взаимодействует с вашим приложением. Это редко используется, потому что, поскольку это должно произойти так быстро, вы, вероятно, можете сделать это непосредственно в главной очереди.

Вы можете проверить эту лекцию, где эта проблема достаточно четко объяснена.

Ответ 5

Основная очередь действительно работает на основном потоке, как вы говорите.

Глобальные очереди - это параллельные очереди и с главной страницы для dispatch_get_global_queue:

В отличие от основной очереди или очередей, распределенных с помощью dispatch_queue_create(), глобальные параллельные очереди планируют блокировать, как только потоки становятся доступными (порядок завершения "не FIFO"). Глобальные параллельные очереди представляют три полосы приоритета:

   •   DISPATCH_QUEUE_PRIORITY_HIGH
   •   DISPATCH_QUEUE_PRIORITY_DEFAULT
   •   DISPATCH_QUEUE_PRIORITY_LOW

Блоки, отправленные в глобальную очередь с высоким приоритетом, будут вызываться до тех, которые представлены в глобальных или невысоких глобальных очередях. Блоки, отправленные в глобальную очередь с низким приоритетом, будут вызываться только в том случае, если блоки не ожидаются в очереди по умолчанию или с высоким приоритетом.

Таким образом, они представляют собой очереди, которые работают по фоновым потокам по мере их появления. Они "не-FIFO", поэтому заказ не гарантируется.