497 votes

NSOperation vs Grand Central Dispatch

J'apprends la programmation concurrente pour iOS. Jusqu'à présent, j'ai lu des articles sur NSOperation / NSOperationQueue y GCD . Quelles sont les raisons d'utiliser NSOperationQueue sur GCD et vice versa ?

On dirait que les deux GCD y NSOperationQueue supprime la création explicite de NSThreads de l'utilisateur. Cependant, la relation entre les deux approches n'est pas claire pour moi, alors tout commentaire sera apprécié !

11 votes

+1 pour la bonne question - curieux des résultats. Jusqu'à présent, j'ai juste lu que GCD peut facilement être distribué à travers les cœurs du CPU, ce qui en fait la "nouvelle merde chaude".

3 votes

Une discussion à ce sujet peut être trouvée dans cette question : Pourquoi devrais-je choisir GCD plutôt que NSOperation et blocs pour les applications de haut niveau ?

1 votes

546voto

BJ Homer Points 29168

GCD est une API de bas niveau en C qui permet une utilisation très simple d'un modèle de concurrence basé sur les tâches. NSOperation y NSOperationQueue sont des classes Objective-C qui font une chose similaire. NSOperation a été introduit en premier, mais à partir de 10.5 y iOS 2 , NSOperationQueue et les amis sont implémentés en interne en utilisant GCD .

En général, vous devez utiliser le plus haut niveau d'abstraction qui convient à vos besoins. Cela signifie que vous devez généralement utiliser NSOperationQueue au lieu de GCD sauf si vous avez besoin de faire quelque chose qui NSOperationQueue ne prend pas en charge.

Notez que NSOperationQueue n'est pas une version "abrutie" de GCD ; en fait, il y a beaucoup de choses que vous pouvez faire très simplement avec NSOperationQueue qui demandent beaucoup de travail avec de purs GCD . (Exemples : files d'attente à bande passante limitée qui ne peuvent exécuter que N opérations à la fois ; établissement de dépendances entre les opérations. Les deux sont très simples avec NSOperation très difficile avec GCD .) Apple a fait le gros du travail en s'appuyant sur GCD pour créer une très belle API conviviale pour les objets avec NSOperation . Profitez de leur travail, sauf si vous avez une raison de ne pas le faire.

Caveat : D'un autre côté, si vous n'avez vraiment besoin que d'envoyer un bloc, et que vous n'avez pas besoin de la fonctionnalité supplémentaire que NSOperationQueue prévoit, il n'y a rien de mal à utiliser le GCD. Assurez-vous simplement que c'est le bon outil pour le travail.

1 votes

NSOperation pour être spécifique une classe abstraite.

3 votes

@Sandy C'est en fait le contraire, GCD est utilisé par NSOperation (au moins dans les dernières versions d'iOS et OS X).

1 votes

@BJ Homer Nous pouvons ajouter une tâche dans une file d'attente de distribution en série pour obtenir la déperdition, alors comment la file d'attente d'opération a un avantage sur cela ?

382voto

Brad Larson Points 122629

En accord avec ma réponse à une question connexe Je ne suis pas d'accord avec BJ et je vous suggère de regarder d'abord GCD plutôt que NSOperation / NSOperationQueue, à moins que ce dernier n'offre quelque chose dont vous avez besoin et que GCD n'offre pas.

Avant GCD, j'utilisais beaucoup de NSOperations / NSOperationQueues dans mes applications pour gérer la concurrence. Cependant, depuis que j'ai commencé à utiliser GCD de façon régulière, j'ai presque entièrement remplacé les NSOperations et les NSOperationQueues par des blocs et des files d'attente de distribution. Cela vient de la façon dont j'ai utilisé ces deux technologies dans la pratique, et du profilage que j'ai effectué sur elles.

Tout d'abord, l'utilisation de NSOperations et de NSOperationQueuesues entraîne une surcharge non négligeable. Ce sont des objets Cocoa, et ils doivent être alloués et désalloués. Dans une application iOS que j'ai écrite et qui rend une scène 3D à 60 FPS, j'utilisais NSOperations pour encapsuler chaque image rendue. Lorsque j'ai établi le profil de cette application, j'ai constaté que la création et le démontage de ces NSOperations représentaient une part importante des cycles CPU de l'application en cours d'exécution, ce qui ralentissait les choses. Je les ai remplacées par de simples blocs et une file d'attente série GCD, et cette surcharge a disparu, ce qui a permis d'améliorer sensiblement les performances de rendu. Ce n'est pas le seul endroit où j'ai remarqué une surcharge due à l'utilisation de NSOperations, et j'ai constaté ce phénomène sur Mac et iOS.

Deuxièmement, il y a une élégance dans le code de répartition basé sur des blocs qu'il est difficile d'égaler en utilisant NSOperations. Il est incroyablement pratique d'envelopper quelques lignes de code dans un bloc et de le répartir pour qu'il soit exécuté sur une file d'attente série ou concurrente, alors que la création d'une NSOperation ou d'une NSInvocationOperation personnalisée pour ce faire nécessite beaucoup plus de code de soutien. Je sais que vous pouvez utiliser une NSBlockOperation, mais vous pourriez tout aussi bien envoyer quelque chose à GCD dans ce cas. Envelopper ce code dans des blocs en ligne avec le traitement connexe dans votre application conduit, à mon avis, à une meilleure organisation du code que d'avoir des méthodes séparées ou des NSOperations personnalisées qui encapsulent ces tâches.

NSOperations et NSOperationQueues ont encore de très bons usages. GCD n'a pas de réel concept de dépendances, alors que NSOperationQueues peut mettre en place des graphes de dépendances assez complexes. J'utilise NSOperationQueues pour cela dans une poignée de cas.

Dans l'ensemble, bien que je préconise généralement l'utilisation du plus haut niveau d'abstraction permettant d'accomplir la tâche, il s'agit d'un cas où je plaide en faveur de l'API de niveau inférieur de GCD. Parmi les développeurs iOS et Mac avec lesquels j'ai discuté de ce sujet, la grande majorité choisit d'utiliser GCD plutôt que NSOperations, à moins qu'ils ne visent des versions du système d'exploitation qui ne le prennent pas en charge (celles antérieures à iOS 4.0 et Snow Leopard).

21 votes

Je ne suis pas tout à fait d'accord ; j'utilise souvent le GCD simple. Mais je pense que vous mettez trop de côté NSBlockOperation dans cette réponse. Tous les avantages de NSOperationQueue (dépendances, débogage, etc.) s'appliquent également aux opérations de bloc.

5 votes

@BJHomer - Je pense que l'évitement de NSBlockOperation est plus une question de préférence personnelle dans mon cas, bien que je me sois éloigné des NSOperations en général après avoir vu l'overhead de leur utilisation tirer vers le bas quelques applications. Si je dois utiliser des blocs, j'ai tendance à opter pour GCD, à l'exception des rares cas où j'ai besoin d'un support des dépendances.

2 votes

+1, merci pour cette analyse. Apple semble prôner les deux (comme la session de la WWDC 2012 sur l'interface utilisateur simultanée), donc c'est très apprécié.

34voto

evanchin Points 359

Une autre raison de préférer NSOperation à GCD est le mécanisme d'annulation de NSOperation. Par exemple, pour une application comme 500px qui affiche des dizaines de photos, NSOperation permet d'annuler les demandes de cellules d'images invisibles lorsque nous faisons défiler la vue tableau ou la vue collection, ce qui peut améliorer considérablement les performances de l'application et réduire l'empreinte mémoire. GCD ne peut pas facilement supporter cela.

Avec la NSOperation, la KVO est également possible.

Ici est un article d'Eschaton qui mérite d'être lu.

4 votes

Il convient de noter que si ce que vous annulez est l'opération réseau de chargement de l'image, alors vous n'avez pas besoin de NSOperation pour cela, comme NSURLSessionTask.cancel y NSURLSession.invalidateAndCancel fournissent cette fonctionnalité. En général, NSURLSession fournit certaines des fonctionnalités d'un NSOperationQueue comme NSURLSessionTask fournit certaines des fonctionnalités d'un NSOperation

0 votes

@algal Comme expliqué ici ( stackoverflow.com/questions/21918722/ ), il semble que la NSURLSession utilise NSOperationQueue comme élément de base.

33voto

das Points 2015

GCD est en effet de niveau inférieur à NSOperationQueue, son principal avantage est que son implémentation est très légère et axée sur les algorithmes sans verrou et les performances.

NSOperationQueue fournit des fonctionnalités qui ne sont pas disponibles dans GCD, mais elles ont un coût non négligeable, l'implémentation de NSOperationQueue est complexe et lourde, implique beaucoup de verrouillage, et n'utilise GCD en interne que de manière très minimale.

Si vous avez besoin des facilités offertes par NSOperationQueue, utilisez-le, mais si GCD est suffisant pour vos besoins, je vous recommande de l'utiliser directement pour de meilleures performances, un coût CPU et énergétique nettement inférieur et plus de flexibilité.

12voto

Dipak Narigara Points 911

Le GCD est un moyen léger de représenter les unités de travail qui vont être exécutées simultanément. Vous ne planifiez pas ces unités de travail, le système s'en charge. système s'en charge pour vous. Ajouter des dépendances entre blocs peut être un casse-tête. L'annulation ou la suspension d'un bloc crée un travail supplémentaire pour vous en tant que développeur !

NSOperation et NSOperationQueue ajoutent un peu plus de frais généraux par rapport à à la GCD, mais vous pouvez ajouter des dépendances entre les différentes opérations. Vous pouvez réutiliser des opérations, les annuler ou les suspendre. NSOperation est compatible avec Key-Value Observation (KVO) ; par exemple, vous pouvez avoir une NSOperation commence à fonctionner en écoutant le NSNotificationCenter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X