web-dev-qa-db-fra.com

Comprendre dispatch_async

J'ai une question autour de ce code

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData* data = [NSData dataWithContentsOfURL: 
      kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:) 
      withObject:data waitUntilDone:YES];
});

Le premier paramètre de ce code est

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

Sommes-nous en train de demander à ce code d’exécuter des tâches en série sur une file globale dont la définition même est de renvoyer une file globale simultanée d’un niveau de priorité donné?

Quel est l'avantage d'utiliser dispatch_get_global_queue sur la file d'attente principale?

Je suis confus. Pourriez-vous s'il vous plaît m'aider à mieux comprendre cela.

227
user2332873

La raison principale pour laquelle vous utilisez la file d'attente par défaut sur la file principale est d'exécuter des tâches en arrière-plan.

Par exemple, si je télécharge un fichier sur Internet et que je souhaite informer l'utilisateur de la progression du téléchargement, je l'exécute dans la file d'attente par défaut prioritaire et je mets à jour l'interface utilisateur de manière asynchrone.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});
502
David

Toutes les files d'attente DISPATCH_QUEUE_PRIORITY_X sont des files d'attente simultanées (ce qui signifie qu'elles peuvent exécuter plusieurs tâches à la fois) et sont FIFO dans le sens où les tâches d'une file d'attente donnée commenceront à s'exécuter en utilisant l'ordre "premier entré, premier sorti". Ceci est comparé à la file d'attente principale (de dispatch_get_main_queue ()), qui est une file d'attente série (les tâches commenceront à s'exécuter et se termineront dans l'ordre dans lequel elles ont été reçues).

Ainsi, si vous envoyez 1000 blocs dispatch_async () à DISPATCH_QUEUE_PRIORITY_DEFAULT, ces tâches commenceront à s'exécuter dans l'ordre que vous leur avez envoyé dans la file d'attente. De même pour les files d'attente HIGH, LOW et BACKGROUND. Tout ce que vous envoyez dans l'une de ces files d'attente est exécuté en arrière-plan sur d'autres threads, loin de votre thread d'application principal. Par conséquent, ces files d'attente conviennent à l'exécution de tâches telles que le téléchargement en arrière-plan, la compression, le calcul, etc.

Notez que l'ordre d'exécution est FIFO par file d'attente. Donc, si vous envoyez 1000 tâches dispatch_async () aux quatre différentes files d’attente simultanées, en les divisant de manière homogène et en les envoyant à BACKGROUND, LOW, DEFAULT et HIGH dans l’ordre (c.-à-d. Que vous planifiez les 250 dernières tâches de la file HIGH), il est très probable que Les premières tâches que vous voyez en train de démarrer seront dans cette file d'attente HIGH, car le système vous a laissé entendre que ces tâches doivent parvenir à la CPU le plus rapidement possible.

Notez également que je dis "commencera à exécuter dans l'ordre", mais gardez à l'esprit que les files d'attente simultanées ne termineront pas nécessairement l'exécution dans l'ordre, en fonction de la durée de chaque tâche.

Selon Apple:

https://developer.Apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Une file d'attente de distribution simultanée est utile lorsque plusieurs tâches peuvent être exécutées en parallèle. Une file d'attente simultanée est toujours une file d'attente dans la mesure où elle met en file d'attente les tâches dans un ordre premier entré, premier sorti. Cependant, une file d'attente simultanée peut retirer de la file d'attente des tâches supplémentaires avant la fin des tâches précédentes. Le nombre réel de tâches exécutées par une file d'attente simultanée à un moment donné est variable et peut changer de manière dynamique à mesure que les conditions de votre application changent. De nombreux facteurs affectent le nombre de tâches exécutées par les files d'attente simultanées, notamment le nombre de cœurs disponibles, la quantité de travail effectuée par d'autres processus, ainsi que le nombre et la priorité des tâches dans les autres files d'attente de distribution en série.

En gros, si vous envoyez ces 1000 blocs dispatch_async () à une file d'attente DEFAULT, HIGH, LOW ou BACKGROUND, ils commenceront tous à s'exécuter dans l'ordre que vous leur aurez envoyé. Cependant, des tâches plus courtes peuvent se terminer avant des tâches plus longues. Cela s'explique par le fait qu'il existe des cœurs de processeur disponibles ou que les tâches de la file d'attente actuelles effectuent un travail non intensif sur le plan des calculs (laissant ainsi le système penser qu'il peut envoyer des tâches supplémentaires en parallèle, quel que soit le nombre de cœurs).

Le niveau de simultanéité est entièrement géré par le système et est basé sur la charge du système et d'autres facteurs déterminés en interne. C'est la beauté de Grand Central Dispatch (le système dispatch_async ()): vous créez simplement vos unités de travail sous forme de blocs de code, leur définissez une priorité (en fonction de la file d'attente choisie) et laissez le système gérer le reste.

Donc, pour répondre à votre question ci-dessus: vous avez partiellement raison. Vous "demandez à ce code" d'exécuter des tâches simultanées sur une file d'attente simultanée globale au niveau de priorité spécifié. Le code du bloc sera exécuté en arrière-plan et tout code supplémentaire (similaire) s'exécutera potentiellement en parallèle, en fonction de l'évaluation des ressources disponibles par le système.

La file "principale" d'autre part (de dispatch_get_main_queue ()) est une file d'attente série (non simultanée). Les tâches envoyées à la file principale s'exécutent toujours dans l'ordre et se terminent toujours dans l'ordre. Ces tâches seront également exécutées sur le thread d'interface utilisateur, ce qui permet de mettre à jour votre interface utilisateur avec des messages de progression, des notifications d'achèvement, etc.

195
SimplePanda

Version rapide

Ceci est la version Swift de la réponse Objective-C de David. Vous utilisez la file d'attente globale pour exécuter des tâches en arrière-plan et la file principale pour mettre à jour l'interface utilisateur.

Swift

DispatchQueue.global(qos: .background).async {

    // Background Thread

    DispatchQueue.main.async {
        // Run UI Updates
    }
}
29
Suragch