NSOperation vs Grand Central Dispatch

465

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

Sonne comme les deux GCDet NSOperationQueuerésume la création explicite NSThreadsde l'utilisateur. Cependant, la relation entre les deux approches n'est pas claire pour moi, donc toute rétroaction est appréciée!

Dimanche Lundi
la source
10
+1 pour une bonne question - curieux des résultats. Jusqu'à présent, je viens de lire que GCD peut facilement être distribué à travers les cœurs de CPU, ce qui en fait la "nouvelle merde chaude".
jusqu'au
3
Une discussion connexe peut être trouvée dans cette question: Pourquoi devrais-je choisir GCD plutôt que NSOperation et les blocs pour les applications de haut niveau?
Brad Larson

Réponses:

517

GCDest une API basée sur C de bas niveau qui permet une utilisation très simple d'un modèle de concurrence basé sur les tâches. NSOperationet NSOperationQueuesont des classes Objective-C qui font une chose similaire. NSOperationa été introduit en premier, mais à partir de 10,5 et iOS 2 , NSOperationQueueet les amis sont implémentés en interne à l'aide GCD.

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

Notez qu'il NSOperationQueuene s'agit pas d'une version "simplifiée" de GCD; en fait, il y a beaucoup de choses que vous pouvez faire très simplement avec NSOperationQueuequi demandent beaucoup de travail avec pure GCD. (Exemples: files d'attente à bande passante limitée qui n'exécutent que N opérations à la fois; établissement de dépendances entre les opérations. Les deux sont très simples avec NSOperation, très difficiles avec GCD.) Apple a fait le travail acharné de tirer parti de GCD pour créer une très jolie API conviviale avec NSOperation. Profitez de leur travail, sauf si vous avez une raison de ne pas le faire.

Mise en garde : D'un autre côté, si vous avez vraiment besoin d'envoyer un bloc et que vous n'avez besoin d'aucune des fonctionnalités supplémentaires NSOperationQueuefournies, il n'y a rien de mal à utiliser GCD. Assurez-vous simplement que c'est le bon outil pour le travail.

BJ Homer
la source
1
NSOperation pour être spécifique d'une classe abstraite.
Roshan
3
@Sandy C'est en fait le contraire, GCD est utilisé par NSOperation (au moins dans les versions ultérieures d'iOS et d'OS X).
garrettmoon
1
@BJ Homer Nous pouvons ajouter une tâche dans la file d'attente de répartition en série pour atteindre la purge. tellement justfy comment la file d'attente des opérations ont un avantage sur cela
Raj Aggrawal
3
@RajAggrawal Oui, cela fonctionne… mais alors vous êtes coincé avec une file d'attente série. NSOperation peut faire "exécuter cette opération une fois ces trois autres terminées, mais en même temps que toutes les autres opérations en cours". Des dépendances d'opération peuvent même exister entre les opérations sur différentes files d'attente. La plupart des gens n'en auront pas besoin, mais si vous le faites, NSOperation serait un meilleur choix.
BJ Homer
369

Conformément à ma réponse à une question connexe , je vais être en désaccord avec BJ et vous suggérer d'abord de regarder GCD sur NSOperation / NSOperationQueue, à moins que ce dernier ne fournisse quelque chose dont vous avez besoin que GCD ne fait 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 régulièrement, j'ai presque entièrement remplacé NSOperations et NSOperationQueues par des blocs et des files d'attente de répartition. Cela vient de la façon dont j'ai utilisé les deux technologies dans la pratique et du profilage que j'ai effectué sur elles.

Tout d'abord, il y a une quantité non négligeable de frais généraux lors de l'utilisation de NSOperations et NSOperationQueues. Ce sont des objets Cocoa, et ils doivent être alloués et désalloués. Dans une application iOS que j'ai écrite qui rend une scène 3D à 60 FPS, j'utilisais NSOperations pour encapsuler chaque image rendue. Lorsque j'ai présenté ce profil, la création et la suppression de ces NSOperations représentaient une partie importante des cycles du processeur dans l'application en cours d'exécution et ralentissaient les choses. J'ai remplacé ceux-ci par de simples blocs et une file d'attente série GCD, et cette surcharge a disparu, conduisant à des performances de rendu sensiblement meilleures. Ce n'était pas le seul endroit où j'ai remarqué des frais généraux en utilisant NSOperations, et je l'ai vu sur Mac et iOS.

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

NSOperations et NSOperationQueues ont toujours de très bonnes utilisations. GCD n'a pas de véritable concept de dépendances, où NSOperationQueues peut configurer des graphiques de dépendance assez complexes. J'utilise NSOperationQueues pour cela dans une poignée de cas.

Dans l'ensemble, alors que je préconise généralement d'utiliser le niveau d'abstraction le plus élevé qui accomplit la tâche, c'est un cas où je plaide pour l'API de niveau inférieur de GCD. Parmi les développeurs iOS et Mac avec lesquels j'ai parlé de cela, la grande majorité choisit d'utiliser GCD sur NSOperations à moins qu'ils ne ciblent des versions de système d'exploitation sans prise en charge (celles avant iOS 4.0 et Snow Leopard).

Brad Larson
la source
20
Je ne suis que légèrement en désaccord; J'utilise un peu GCD ordinaire. Mais je pense que vous négligez trop NSBlockOperation dans cette réponse. Tous les avantages de NSOperationQueue (dépendances, débogage, etc.) s'appliquent également aux opérations de bloc.
BJ Homer
4
@BJHomer - Je pense que l'évitement de NSBlockOperation est plus une question de préférence personnelle dans mon cas, bien que j'ai évité NSOperations en général après avoir vu les frais généraux de leur utilisation faire glisser quelques applications. Si je vais utiliser des blocs, j'ai tendance à miser sur GCD, à la rare exception lorsque j'ai besoin d'un support de dépendance.
Brad Larson
1
+1, merci pour cette analyse. Apple semble préconiser les deux (comme la session de la WWDC 2012 sur l'interface utilisateur simultanée), c'est donc très apprécié.
orip
1
@VolureDarkAngel - GCD est extrêmement rapide à gérer des envois comme celui-ci. Cela ne devrait pas être votre goulot d'étranglement dans une situation comme vous le décrivez, à moins que vous ne sauvegardiez d'une manière ou d'une autre une pile de mises à jour dans une file d'attente en raison de l'accès aux E / S lent ou quelque chose du genre. Ce n'est probablement pas le cas ici, cependant.
Brad Larson
1
@ asma22 - Il est courant d'avoir des calculs qui peuvent être effectués en morceaux, mais le calcul final d'une étape peut nécessiter les résultats de plusieurs étapes précédentes. Dans ce cas, vous pouvez faire en sorte que cette opération ultérieure dépende des opérations antérieures, et la planification sera gérée de telle sorte que toutes soient terminées avant la dernière exécution.
Brad Larson
101

GCDest une API basique basée sur C.
NSOperationet NSOperationQueuesont des classes Objective-C.
NSOperationQueueest wrapper objectif C sur GCD. Si vous utilisez NSOperation, vous utilisez implicitement Grand Central Dispatch.

Avantage GCD par rapport à NSOperation:
i. mise en œuvre
Pour la GCDmise en œuvre est très léger
NSOperationQueueest complexe et lourd

Avantages de NSOperation par rapport à GCD:

je. Contrôle du fonctionnement,
vous pouvez suspendre, annuler, reprendre unNSOperation

ii. Les dépendances que
vous pouvez configurer une dépendance entre deux NSOperations
opérations ne seront pas démarrées tant que toutes ses dépendances ne seront pas vérifiées pour terminées.

iii. L'état de fonctionnement
peut surveiller l'état d'une opération ou d'une file d'attente d'opérations. prêt, en cours d'exécution ou terminé

iv. Nombre
maximal d'opérations, vous pouvez spécifier le nombre maximal d'opérations en file d'attente pouvant s'exécuter simultanément

Quand y aller GCDouNSOperation
quand vous voulez plus de contrôle sur l'utilisation de la file d'attente (tous mentionnés ci-dessus) NSOperation et pour les cas simples où vous voulez moins de surcharge (vous voulez juste faire du travail "en arrière-plan" avec très peu de travail supplémentaire)GCD

réf:
https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html http : //nshipster.com/nsoperation/

Sangram Shivankar
la source
Comme indiqué, le nombre maximal d'opérations peut être spécifié dans NSOperationQueue, alors quel peut être le nombre maximal d'opérations (files d'attente de répartition) dans GCD? Supposons que j'ai un projet, alors combien d'opérations (files d'attente de répartition) puis-je faire. ou leur est toute limite maximale jusqu'à laquelle nous pouvons faire.
Roshan Sah
Cela dépend des conditions du système. Voici des informations détaillées: stackoverflow.com/questions/14995801/…
Sangram Shivankar
Nous pouvons également annuler la tâche dans GCD à l'aide de DispatchWorkItem et nous pouvons également suspendre et reprendre
Ankit garg
@Ankitgarg L'appel d'annulation sur DispatchWorkItem arrêtera l'exécution des tâches si elles n'ont pas encore été exécutées, mais n'arrêtera pas quelque chose qui est déjà en cours d'exécution. et comment mettre en pause / reprendre un DispatchWorkItem ??
abhimuralidharan
34

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

Aussi avec NSOperation, KVO peut être possible.

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

evanchin
la source
4
Il convient de noter que si ce que vous annulez est l'opération réseau de chargement de l'image, vous n'en avez pas besoin NSOperation, car NSURLSessionTask.cancelet NSURLSession.invalidateAndCancelfournissez cette fonctionnalité. En général, NSURLSessionfournit certaines des fonctionnalités d'un NSOperationQueue, comme NSURLSessionTaskfournit certaines des fonctionnalités d'unNSOperation
algal
@algal Comme expliqué ici ( stackoverflow.com/questions/21918722/… ), il semble que NSURLSession utilise NSOperationQueue comme bloc de construction.
kalan nawarathne
33

GCD est en effet de niveau inférieur à NSOperationQueue, son principal avantage est que sa mise en œuvre est très légère et axée sur des algorithmes et des performances sans verrouillage.

NSOperationQueue fournit des installations qui ne sont pas disponibles dans GCD, mais elles ont un coût non négligeable, la mise en œuvre de NSOperationQueue est complexe et lourde, implique beaucoup de verrouillage et utilise GCD en interne uniquement de manière très minimale.

Si vous avez besoin que les installations fournies par NSOperationQueue l'utilisent par tous les moyens, mais si GCD est suffisant pour vos besoins, je recommanderais de l'utiliser directement pour de meilleures performances, des coûts de processeur et d'alimentation considérablement inférieurs et plus de flexibilité.

das
la source
24

NSQueueOperations et GCD permettent d'exécuter une tâche de calcul lourde en arrière-plan sur des threads distincts en libérant la bande de roulement principale de l'application d'interface utilisateur.

Eh bien, sur la base du post précédent, nous voyons que NSOperations a addDependency afin que vous puissiez mettre votre opération en file d'attente l'une après l'autre de manière séquentielle.

Mais j'ai également lu sur les files d'attente série GCD que vous pouvez créer, exécutez vos opérations dans la file d'attente à l'aide de dispatch_queue_create. Cela permettra d'exécuter un ensemble d'opérations les unes après les autres de manière séquentielle.

Avantages de NSQueueOperation par rapport à GCD:

  1. Il permet d'ajouter des dépendances et vous permet de supprimer les dépendances. Ainsi, pour une transaction, vous pouvez exécuter séquentiellement en utilisant la dépendance et pour les autres transactions exécutées simultanément tandis que GCD ne permet pas de s'exécuter de cette façon.

  2. Il est facile d'annuler une opération si elle est dans la file d'attente, elle peut être arrêtée si elle est en cours d'exécution.

  3. Vous pouvez définir le nombre maximal d'opérations simultanées.

  4. Vous pouvez suspendre le fonctionnement qu'ils sont en file d'attente

  5. Vous pouvez trouver le nombre d'opérations en attente dans la file d'attente.

Shashi3456643
la source
6

GCD est très facile à utiliser - si vous voulez faire quelque chose en arrière-plan, tout ce que vous avez à faire est d'écrire le code et de l'envoyer dans une file d'attente en arrière-plan. Faire la même chose avec NSOperation représente beaucoup de travail supplémentaire.

L'avantage de NSOperation est que (a) vous avez un objet réel auquel vous pouvez envoyer des messages, et (b) que vous pouvez annuler une NSOperation. Ce n'est pas anodin. Vous devez sous-classer NSOperation, vous devez écrire votre code correctement pour que l'annulation et la fin correcte d'une tâche fonctionnent correctement. Donc, pour les choses simples, vous utilisez GCD, et pour les choses plus compliquées, vous créez une sous-classe de NSOperation. (Il existe des sous-classes NSInvocationOperation et NSBlockOperation, mais tout ce qu'elles font est plus facile à faire avec GCD, il n'y a donc aucune bonne raison de les utiliser).

gnasher729
la source
3

Eh bien, NSOperations est simplement une API construite au-dessus de Grand Central Dispatch. Donc, lorsque vous utilisez NSOperations, vous utilisez vraiment toujours Grand Central Dispatch. C'est juste que NSOperations vous offre des fonctionnalités fantaisistes qui pourraient vous plaire. Vous pouvez rendre certaines opérations dépendantes d'autres opérations, réorganiser les files d'attente après avoir ajouté des éléments, etc. En fait, ImageGrabber utilise déjà NSOperations et les files d'attente d'opérations! ASIHTTPRequest les utilise sous le capot et vous pouvez configurer la file d'attente d'opérations qu'il utilise pour un comportement différent si vous le souhaitez. Alors, que devez-vous utiliser? Selon ce qui est logique pour votre application. Pour cette application, c'est assez simple, nous avons donc utilisé directement Grand Central Dispatch, pas besoin des fonctionnalités sophistiquées de NSOperation. Mais si vous en avez besoin pour votre application, n'hésitez pas à l'utiliser!

Ankul Gaur
la source