Поиск…


Вступление

Grand Central Dispatch (GCD) - ответ Apple на многопоточность. Это облегченная структура для выполнения задач синхронно или асинхронно в очередях и обрабатывает потоки ЦП для вас за кулисами.

Связанная тема: параллелизм

Создание очереди отправки

Вы можете создать свою собственную очередь, используя dispatch_queue_create

Objective-C

dispatch_queue_t queue = dispatch_queue_create("com.example.myqueue",  DISPATCH_QUEUE_SERIAL);

стриж

// Before Swift 3
let queue = dispatch_queue_create("com.example.myqueue", DISPATCH_QUEUE_SERIAL)
// Swift 3
let queue = DispatchQueue(label: "com.example.myqueue") //default is serial queue, unless .concurrent is specified as an attribute otherwise

Получение главной очереди

Главной очередью является очередь отправки, в которой все обновления пользовательского интерфейса, и код с изменениями пользовательского интерфейса.

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

Существует два типа вызовов основной очереди: synchronous и asynchronous . Когда вы вызываете что-то synchronously , это означает, что поток, инициировавший эту операцию, будет ждать завершения задачи перед продолжением. Asynchronous означает, что он не будет ждать.

Цель кода-C

Synchronous вызов главной очереди

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Asynchronous вызов главной очереди

dispatch_async(dispatch_get_main_queue(), ^{
   // do work here to Usually to update the User Interface
});

SWIFT 3

Asynchronous вызов главной очереди

DispatchQueue.main.async {

}

Synchronous вызов главной очереди

DispatchQueue.main.sync {

}

Диспетчерская группа

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

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

Swift 3

func doLongTasksAndWait () {
    print("starting long running tasks")
    let group = DispatchGroup()          //create a group for a bunch of tasks we are about to do
    for i in 0...3 {                     //launch a bunch of tasks (eg a bunch of webservice calls that all need to be finished before proceeding to the next ViewController)
        group.enter()                    //let the group know that something is being added
        DispatchQueue.global().async {   //run tasks on a background thread
            sleep(arc4random() % 4)      //do some long task eg webservice or database lookup (here we are just sleeping for a random amount of time for demonstration purposes)
            print("long task \(i) done!")
            group.leave()                //let group know that the task is finished
        }
    }
    group.wait()                         //will block whatever thread we are on here until all the above tasks have finished (so maybe dont use this function on your main thread)
    print("all tasks done!")
}

С другой стороны , если вы не хотите ждать , пока группы , чтобы закончить, но вместо этого хочет , чтобы запустить функцию , когда все задачи выполнили, используйте notify функцию вместо group.wait()

group.notify(queue: DispatchQueue.main) { //the queue: parameter is which queue this block will run on, if you need to do UI updates, use the main queue
    print("all tasks done!")              //this will execute when all tasks have left the group
}

Пример вывода:

starting long running tasks
long task 0 done!
long task 3 done!
long task 1 done!
long task 2 done!
all tasks done!

Для получения дополнительной информации см. Документы Apple или соответствующую тему

Диспетчерский семафор

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

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

Swift 3

func do2TasksAtATime () {
    print("starting long running tasks (2 at a time)")
    let sem = DispatchSemaphore(value: 2)            //this semaphore only allows 2 tasks to run at the same time (the resource count)
    for i in 0...7 {                                 //launch a bunch of tasks
        DispatchQueue.global().async {               //run tasks on a background thread
            sem.wait()                               //wait here if no resources available
            sleep(2)                                 //do some long task eg file access (here we are just sleeping for a 2 seconds for demonstration purposes)
            print("long task \(i) done! \(Date())")
            sem.signal()                             //let the semaphore know this resource is now available
        }
    }
}

Пример вывода: (обратите внимание на отметки времени)

starting long running tasks (2 at a time)
long task 0 done! 2017-02-16 07:11:53 +0000
long task 1 done! 2017-02-16 07:11:53 +0000
long task 2 done! 2017-02-16 07:11:55 +0000
long task 3 done! 2017-02-16 07:11:55 +0000
long task 5 done! 2017-02-16 07:11:57 +0000
long task 4 done! 2017-02-16 07:11:57 +0000
long task 6 done! 2017-02-16 07:11:59 +0000
long task 7 done! 2017-02-16 07:11:59 +0000

Для получения дополнительной информации см. Документы Apple

Серийные и параллельные диспетчерские очереди

Swift 3

Серийная очередь

func serialQueues () {
    let serialQueue = DispatchQueue(label: "com.example.serial") //default queue type is a serial queue
    let start = Date ()
    for i in 0...3 {                                             //launch a bunch of tasks
        serialQueue.async {                                      //run tasks on a background thread, using our serial queue
            sleep(2)                                             //do some long task eg webservice or database lookup
            let timeTaken = Date().timeIntervalSince(start)
            print("serial long task \(i) done! total time taken: \(timeTaken)")
        }
    }
}

Пример вывода:

serial long task 0 done! total time taken: 2.07241100072861
serial long task 1 done! total time taken: 4.16347700357437
serial long task 2 done! total time taken: 6.23209798336029
serial long task 3 done! total time taken: 8.30682599544525

Параллельная очередь

func concurrentQueues () {
    let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent) //explicitly specify the queue to be a concurrent queue
    let start = Date ()
    for i in 0...3 {            //launch a bunch of tasks
        concurrentQueue.async { //run tasks on a background thread, using our concurrent queue
            sleep(2)            //do some long task eg webservice or database lookup
            let timeTaken = Date().timeIntervalSince(start)
            print("concurrent long task \(i) done! total time taken: \(timeTaken)")
        }
    }
}

Пример вывода:

concurrent long task 3 done! total time taken: 2.07092100381851
concurrent long task 0 done! total time taken: 2.07087397575378
concurrent long task 2 done! total time taken: 2.07086700201035
concurrent long task 1 done! total time taken: 2.07089096307755

обсуждение

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

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



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