Поиск…


Синтаксис

  • Swift 3.0

  • DispatchQueue.main // Получить основную очередь

  • DispatchQueue (метка: «my-serial-queue», атрибуты: [.serial, .qosBackground]) // Создайте свою собственную приватную последовательную очередь

  • DispatchQueue.global (атрибуты: [.qosDefault]) // Доступ к одной из глобальных параллельных очередей

  • DispatchQueue.main.async {...} // Отправлять задачу асинхронно в основной поток

  • DispatchQueue.main.sync {...} // Отправлять задачу синхронно с основным потоком

  • DispatchQueue.main.asyncAfter (крайний срок: .now () + 3) {...} // Отправлять задачу асинхронно в основной поток, который будет выполняться через x секунд

  • Swift <3.0

  • dispatch_get_main_queue () // Получить основную очередь, запущенную в основном потоке

  • dispatch_get_global_queue (dispatch_queue_priority_t, 0) // Получить глобальную очередь с указанным приоритетом dispatch_queue_priority_t

  • dispatch_async (dispatch_queue_t) {() -> Void in ...} // Отправлять задачу асинхронно по указанному dispatch_queue_t

  • dispatch_sync (dispatch_queue_t) {() -> Void in ...} // Отправлять задачу синхронно на указанный dispatch_queue_t

  • dispatch_after (dispatch_time (DISPATCH_TIME_NOW, Int64 (наносекунды)), dispatch_queue_t, {...}); // Отправляем задачу на указанный dispatch_queue_t после наносекунд

Получение очереди Grand Central Dispatch (GCD)

Grand Central Dispatch работает над концепцией «Dispatch Queues». Очередь отправки выполняет задачи, которые вы назначаете в том порядке, в котором они передаются. Существует три типа диспетчерских очередей:

  • Последовательные диспетчерские очереди (например, частные очереди отправки) выполняют одну задачу за раз, по порядку. Они часто используются для синхронизации доступа к ресурсу.
  • Параллельные диспетчерские очереди (например, глобальные очереди отправки) выполняют одну или несколько задач одновременно.
  • Основная очередь диспетчера выполняет задачи в основном потоке.

Для доступа к основной очереди:

3.0
let mainQueue = DispatchQueue.main
3.0
let mainQueue = dispatch_get_main_queue()

Система предоставляет параллельные глобальные очереди отправки (глобальные для вашего приложения) с различными приоритетами. Вы можете получить доступ к этим очередям, используя класс DispatchQueue в Swift 3:

3.0
let globalConcurrentQueue = DispatchQueue.global(qos: .default)

эквивалентно

let globalConcurrentQueue = DispatchQueue.global()
3.0
let globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

В iOS 8 или более поздних версиях возможные значения качества обслуживания, которые могут быть переданы, являются .userInteractive , .userInitiated , .default , .utility и .background . Они заменяют константы DISPATCH_QUEUE_PRIORITY_ .

Вы также можете создавать свои собственные очереди с различными приоритетами:

3.0
let myConcurrentQueue = DispatchQueue(label: "my-concurrent-queue", qos: .userInitiated, attributes: [.concurrent], autoreleaseFrequency: .workItem, target: nil)
let mySerialQueue = DispatchQueue(label: "my-serial-queue", qos: .background, attributes: [], autoreleaseFrequency: .workItem, target: nil)
3.0
let myConcurrentQueue = dispatch_queue_create("my-concurrent-queue", DISPATCH_QUEUE_CONCURRENT)
let mySerialQueue = dispatch_queue_create("my-serial-queue", DISPATCH_QUEUE_SERIAL)

В Swift 3 очереди, созданные с помощью этого инициализатора, по умолчанию являются серийными, а передача .workItem для частоты автоопределения обеспечивает создание и удаление пула автозапуска для каждого рабочего элемента. Существует также .never , что означает, что вы сами будете управлять собственными пулами автозапуска, или .inherit который наследует настройку из среды. В большинстве случаев вы, вероятно, не будете использовать. .never кроме случаев экстремальной настройки.

Выполнение задач в очереди Grand Central Dispatch (GCD)

3.0

Чтобы запускать задачи в очереди отправки, используйте методы sync , async и after .

Чтобы отправить задачу в очередь асинхронно:

let queue = DispatchQueue(label: "myQueueName")

queue.async {
    //do something
    
    DispatchQueue.main.async {
        //this will be called in main thread
        //any UI updates should be placed here
    }
}
// ... code here will execute immediately, before the task finished

Чтобы отправить задачу в очередь синхронно:

queue.sync {
    // Do some task
}
// ... code here will not execute until the task is finished

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

queue.asyncAfter(deadline: .now() + 3) {
    //this will be executed in a background-thread after 3 seconds
}
// ... code here will execute immediately, before the task finished

ПРИМЕЧАНИЕ. Любые обновления пользовательского интерфейса должны быть вызваны в основной поток! Убедитесь, что вы разместили код для обновлений пользовательского интерфейса внутри DispatchQueue.main.async { ... }

2,0

Типы очереди:

let mainQueue = dispatch_get_main_queue()
let highQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
let backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)

Чтобы отправить задачу в очередь асинхронно:

dispatch_async(queue) {
    // Your code run run asynchronously. Code is queued and executed 
    // at some point in the future.
}
// Code after the async block will execute immediately

Чтобы отправить задачу в очередь синхронно:

dispatch_sync(queue) {
    // Your sync code
}
// Code after the sync block will wait until the sync task finished

Чтобы отправить задание через промежуток времени (используйте NSEC_PER_SEC для преобразования секунд в наносекунды):

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
    // Code to be performed in 2.5 seconds here
}

Чтобы выполнить задачу асинхронно и обновить пользовательский интерфейс:

dispatch_async(queue) {
    // Your time consuming code here
    dispatch_async(dispatch_get_main_queue()) {
        // Update the UI code 
    }
}

ПРИМЕЧАНИЕ. Любые обновления пользовательского интерфейса должны быть вызваны в основной поток! Убедитесь, что вы разместили код для обновлений пользовательского интерфейса внутри dispatch_async(dispatch_get_main_queue()) { ... }

Контурные петли

GCD обеспечивает механизм для выполнения цикла, посредством чего петли происходят одновременно друг с другом. Это очень полезно при выполнении серии дорогостоящих вычислений.

Рассмотрим этот цикл:

for index in 0 ..< iterations {
    // Do something computationally expensive here
}

Вы можете выполнять эти вычисления одновременно с помощью concurrentPerform (в Swift 3) или dispatch_apply (в Swift 2):

3.0
DispatchQueue.concurrentPerform(iterations: iterations) { index in
    // Do something computationally expensive here
}
3.0
dispatch_apply(iterations, queue) { index in
    // Do something computationally expensive here
}

Закрытие цикла будет вызываться для каждого index от 0 до, но не включая, iterations . Эти итерации будут выполняться одновременно друг с другом, и, следовательно, порядок, в котором они выполняются, не гарантируется. Фактическое количество итераций, которые происходят одновременно в любой момент времени, обычно определяется возможностями соответствующего устройства (например, сколько ядер имеет устройство).

Несколько особых соображений:

  • Параметр concurrentPerform / dispatch_apply может запускать циклы одновременно друг относительно друга, но все это происходит синхронно по отношению к потоку, из которого вы его вызываете. Поэтому не называйте это из основного потока, так как это блокирует этот поток до тех пор, пока цикл не будет выполнен.

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

  • Обратите внимание: в запуске параллельных циклов есть некоторые служебные данные. Таким образом, если вычисления, выполняемые внутри цикла, недостаточно интенсивно вычислительны, вы можете обнаружить, что любая производительность, получаемая при использовании параллельных циклов, может быть уменьшена, если не быть полностью компенсированной, служебными данными, связанными с синхронизацией всех этих параллельных потоков.

    Таким образом, вы отвечаете за определение правильного количества работы, которое должно выполняться на каждой итерации цикла. Если вычисления слишком просты, вы можете использовать «шагание», чтобы включить больше работы за цикл. Например, вместо выполнения параллельного цикла с 1 миллионом тривиальных вычислений вы можете выполнить 100 итераций в своем цикле, выполняя 10 000 вычислений на цикл. Таким образом, в каждом потоке выполняется достаточная работа, поэтому накладные расходы, связанные с управлением этими параллельными циклами, становятся менее значительными.

Выполнение задач в OperationQueue

Вы можете думать о OperationQueue как о линии задач, ожидающих исполнения. В отличие от диспетчерских очередей в GCD, очереди операций не являются FIFO (first-in-first-out). Вместо этого они выполняют задачи, как только они готовы к выполнению, если для этого достаточно системных ресурсов.

Получить главный OperationQueue :

3.0
let mainQueue = OperationQueue.main

Создайте пользовательский режим OperationQueue :

3.0
let queue = OperationQueue()
queue.name = "My Queue"
queue.qualityOfService = .default

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

Добавить Operation в OperationQueue :

3.0
// An instance of some Operation subclass
let operation = BlockOperation {
    // perform task here
}

queue.addOperation(operation)

Добавьте блок к OperationQueue :

3.0
myQueue.addOperation {
    // some task
}

Добавьте несколько Operation s в OperationQueue :

3.0
let operations = [Operation]()
// Fill array with Operations

myQueue.addOperation(operations)

Отрегулируйте, сколько Operation s может выполняться одновременно в очереди:

myQueue.maxConcurrentOperationCount = 3 // 3 operations may execute at once

// Sets number of concurrent operations based on current system conditions
myQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount

Приостановка очереди предотвратит запуск каких-либо существующих, нераспределенных операций или любых новых операций, добавленных в очередь. Способ возобновления этой очереди заключается в том, isSuspended вернуть isSuspended в значение false :

3.0
myQueue.isSuspended = true

// Re-enable execution
myQueue.isSuspended = false

Приостановка OperationQueue не останавливает или отменяет выполняемые операции. Нужно только попытаться приостановить создавшуюся очередь, а не глобальные очереди или основную очередь.

Создание высокоуровневых операций

Структура Foundation предоставляет тип Operation , который представляет объект высокого уровня, который инкапсулирует часть работы, которая может выполняться в очереди. Координация не только координирует работу этих операций, но также позволяет устанавливать зависимости между операциями, создавать отмененные операции, ограничивать степень параллелизма, применяемую в очереди операций, и т. Д.

Operation готова к выполнению, когда все ее зависимости завершены. Свойство isReady затем изменяется на true .

Создайте простой неавтоматический подкласс Operation :

3.0
class MyOperation: Operation {

    init(<parameters>) {
        // Do any setup work here
    }

    override func main() {
        // Perform the task
    }

}
2,3
class MyOperation: NSOperation {

    init(<parameters>) {
        // Do any setup work here
    }

    override func main() {
        // Perform the task
    }

}

Добавьте операцию в OperationQueue :

1,0
myQueue.addOperation(operation)

Это будет выполнять операцию одновременно в очереди.

Управление зависимостями от Operation .

Зависимости определяют другие Operation s, которые должны выполняться в очереди до того, как Operation считается готовой к выполнению.

1,0
operation2.addDependency(operation1)

operation2.removeDependency(operation1)

Запуск Operation без очереди:

1,0
   operation.start()

Зависимости будут проигнорированы. Если это параллельная операция, задача может выполняться одновременно, если ее метод start работает в фоновых очередях.

Параллельные операции.

Если задача, которую выполняет Operation , сама, асинхронная (например, URLSession данных URLSession ), вы должны реализовать Operation как параллельную операцию. В этом случае ваша isAsynchronous реализация должна возвращать значение true , обычно у вас есть метод start который выполняет некоторую настройку, а затем вызывает его main метод, который фактически выполняет задачу.

При isExecuting асинхронной Operation вы должны реализовать isExecuting , isFinished methods и isFinished . Таким образом, при запуске isExecuting свойство isExecuting изменяется на true . Когда Operation завершает свою задачу, isExecuting устанавливается в false , а isFinished - true . Если операция отменена, оба isCancelled и isFinished изменяются на true . Все эти свойства являются наблюдаемыми по ключевым значениям.

Отмените Operation .

Вызов cancel просто изменяет свойство isCancelled на true . Чтобы отреагировать на отмену в пределах вашего собственного подкласса Operation , вы должны проверить значение isCancelled по крайней мере, периодически в пределах main и соответствующим образом реагировать.

1,0
operation.cancel()


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow