Recherche…


Introduction

Grand Central Dispatch (GCD) est la réponse d'Apple au multithreading. Il s'agit d'une infrastructure légère permettant d'effectuer des tâches de manière synchrone ou asynchrone dans les files d'attente et de gérer les threads de CPU pour vous dans les coulisses.

Rubrique connexe: Concurrence

Créer une file d'attente de distribution

Vous pouvez créer votre propre file d'attente en utilisant dispatch_queue_create

Objectif c

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

Rapide

// 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

Obtenir la file d'attente principale

La file d'attente principale est la file d'attente de distribution dans laquelle toutes les mises à jour de l'interface utilisateur ont lieu et le code impliquant les modifications de l'interface utilisateur est placé.

Vous devez accéder à la file d'attente principale afin de mettre à jour l'interface utilisateur à la fin d'un processus asynchrone tel que NSURLSession

Il existe deux types d'appels de file d'attente principale synchronous et asynchronous . Lorsque vous appelez quelque chose de manière synchronously , cela signifie que le thread qui a lancé cette opération attend que la tâche se termine avant de continuer. Asynchronous signifie qu'il n'attendra pas.

Code Objective-C

Appel de la file d'attente principale Synchronous

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Appel de file d'attente principale Asynchronous

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

SWIFT 3

Appel de file d'attente principale Asynchronous

DispatchQueue.main.async {

}

Appel de la file d'attente principale Synchronous

DispatchQueue.main.sync {

}

Groupe d'expédition

DispatchGroup permet la synchronisation globale du travail. Vous pouvez les utiliser pour soumettre plusieurs éléments de travail différents et effectuer un suivi lorsqu'ils sont tous terminés, même s'ils peuvent s'exécuter sur des files d'attente différentes. Ce comportement peut être utile lorsque la progression ne peut pas être effectuée tant que toutes les tâches spécifiées ne sont pas terminées.

Un scénario, si cela peut être utile, si vous avez plusieurs appels de services Web qui doivent tous être terminés avant de continuer. Par exemple, vous devez télécharger plusieurs ensembles de données devant être traités par une fonction. Vous devez attendre que tous les services Web soient terminés avant d'appeler la fonction pour traiter toutes les données reçues.

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!")
}

Sinon, si vous ne souhaitez pas attendre la fin des groupes, mais que vous souhaitez exécuter une fonction une fois toutes les tâches terminées, utilisez la fonction notify à la place du 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
}

Exemple de sortie:

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

Pour plus d'informations, reportez-vous à la documentation Apple ou à la rubrique associée.

Sémaphore d'expédition

DispatchSemaphore fournit une implémentation efficace d'un sémaphore de comptage traditionnel, qui peut être utilisé pour contrôler l'accès à une ressource dans plusieurs contextes d'exécution.

Un scénario pour savoir quand utiliser un sémaphore peut être si vous faites de la lecture / écriture de fichiers, si plusieurs tâches essaient de lire et d’écrire en même temps, cela peut augmenter vos performances pour que chaque tâche attende son tour. pour ne pas surcharger le contrôleur d'E / S.

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
        }
    }
}

Exemple de sortie: (notez les horodatages)

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

Pour plus d'informations, consultez le document Apple Docs

Files d'attente de répartition série / simultanée

Swift 3

File d'attente série

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)")
        }
    }
}

Exemple de sortie:

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

File d'attente simultanée

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)")
        }
    }
}

Exemple de sortie:

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

Discussion

Comme nous pouvons le voir dans les exemples ci-dessus, une file d'attente série complète chaque tâche dans l'ordre dans lequel elles sont soumises à la file d'attente. Chaque tâche attend que la tâche précédente se termine avant de l'exécuter. En ce qui concerne la file d'attente concurrente, chaque tâche n'attend pas les autres en attente et s'exécute dès que possible. L'avantage est que toutes les tâches de la file d'attente s'exécuteront en même temps sur des threads distincts, ce qui fait qu'une file d'attente simultanée prend moins de temps qu'une file d'attente en série.

Si l'ordre d'exécution des tâches n'est pas important, utilisez toujours une file d'attente simultanée pour optimiser l'efficacité.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow