Можно ли указать `DispatchQueue` для` DispatchQueue.concurrentPerform`? - PullRequest
0 голосов
/ 20 февраля 2019

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

Насколько я понимаю, подразумевается DispatchQueue.concurrentPerform в Swiftзаменить dispatch_apply.Но эта функция не принимает очередь отправки в качестве параметра.После поиска, я нашел этот учебник GCD , который имеет этот код:

let _ = DispatchQueue.global(qos: .userInitiated)
DispatchQueue.concurrentPerform(iterations: addresses.count) { index in
    // do work here
}

И объясняет:

Эта реализация включает в себя любопытную строку кода:let _ = DispatchQueue.global(qos: .userInitiated).Вызов этого говорит заставляет GCD использовать очередь с качеством обслуживания .userInitiated для одновременных вызовов.

Мой вопрос, действительно ли это работает для определения QoS?Если да, то как?

Для меня может иметь смысл, что нет способа указать очередь для этого, потому что последовательная очередь не имеет смысла в этом контексте, и только самое высокое QoS действительно имеет смысл, учитываячто это синхронная блокирующая функция.Но я не могу найти никакой документации относительно того, почему можно указать очередь с dispatch_apply, но невозможно (?) С DispatchQueue.concurrentPerform.

1 Ответ

0 голосов
/ 20 февраля 2019

Попытка автора указать качество обслуживания очереди (QoS) неверна.concurrentPerform использует QoS текущей очереди, если может.Вы можете подтвердить это, отследив исходный код:

  1. concurrentPerform, звонки _swift_dispatch_apply_current.

  2. _swift_dispatch_apply_current звонки dispatch_apply с 0, т. Е. DISPATCH_APPLY_AUTO, что определяется как a ...

    ... Константаперейти к dispatch_apply() или dispatch_apply_f(), чтобы запросить, чтобы система автоматически использовала рабочие потоки, которые максимально точно соответствуют конфигурации текущего потока.

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

  3. Это также можно подтвердить, выполнив dispatch_apply call dispatch_apply_f при котором DISPATCH_APPLY_AUTO приводит к вызову _dispatch_apply_root_queue.Если вы продолжите сворачивать кроличью нору в swift-corelibs-libdispatch , вы увидите, что на самом деле она использует глобальную очередь, которая совпадает с QoS вашего текущего потока.

Итог, правильный способ указать QoS - отправить вызов на concurrentPerform в нужную очередь, например:

DispatchQueue.global(qos: .userInitiated).async {
    DispatchQueue.concurrentPerform(iterations: 3) { (i) in
        ...
    }
}

Это легко проверить эмпирически, добавив точку остановаи глядя на очередь в отладчике XCode:

enter image description here


Излишне говорить, что предложение добавить let _ = ... неверно.Рассмотрим следующее:

DispatchQueue.global(qos: .utility).async {
    let _ = DispatchQueue.global(qos: .userInitiated)

    DispatchQueue.concurrentPerform(iterations: 3) { (i) in
        ...
    }
}

Это будет работать с «служебным» QoS, а не «инициированным пользователем».

Опять же, это легко проверить эмпирически:

enter image description here


См. Видео WWDC 2017 Модернизация Grand Central Dispatch для обсуждения вопросов DISPATCH_APPLY_AUTO и concurrentPerform.

...