NSOperation vs Grand Central Dispatch


465

Sto imparando la programmazione concorrente per iOS. Finora ho letto di NSOperation/NSOperationQueue e GCD. Quali sono i motivi per usare NSOperationQueueover GCDe viceversa?

Suoni come sia GCDe NSOperationQueueastrarre la creazione esplicita NSThreadsda parte dell'utente. Tuttavia la relazione tra i due approcci non mi è chiara, quindi qualsiasi feedback da apprezzare!


10
+1 per una buona domanda - curioso sui risultati. Finora, ho appena letto che GCD può essere facilmente inviato attraverso i core della CPU, rendendolo la "nuova merda calda".
Fino al

3
In questa domanda è possibile trovare alcune discussioni correlate: Perché dovrei scegliere GCD su NSOperation e blocchi per applicazioni di alto livello?
Brad Larson

Risposte:


517

GCDè un'API di basso livello basata su C che consente un utilizzo molto semplice di un modello di concorrenza basato su attività. NSOperatione NSOperationQueuesono classi Objective-C che fanno una cosa simile. NSOperationè stato introdotto per primo, ma a partire da 10.5 e iOS 2 , NSOperationQueuee gli amici sono implementati internamente utilizzando GCD.

In generale, è necessario utilizzare il massimo livello di astrazione adatto alle proprie esigenze. Questo significa che di solito dovresti usare NSOperationQueueinvece di GCD, a meno che tu non debba fare qualcosa che NSOperationQueuenon supporta.

Nota che NSOperationQueuenon è una versione "stupida" di GCD; in effetti, ci sono molte cose che puoi fare in modo molto semplice NSOperationQueueche richiedono molto lavoro con puro GCD. (Esempi: code limitate dalla larghezza di banda che eseguono solo operazioni N alla volta; stabilire dipendenze tra operazioni. Entrambi molto semplici con NSOperation, molto difficili con GCD.) Apple ha fatto il duro lavoro di sfruttare GCD per creare un'API molto intuitiva con gli oggetti NSOperation. Approfitta del loro lavoro a meno che tu non abbia un motivo per non farlo.

Avvertenza : d'altra parte, se hai davvero bisogno di inviare un blocco e non hai bisogno di nessuna delle funzionalità aggiuntive che NSOperationQueuefornisce, non c'è niente di sbagliato nell'utilizzo di GCD. Basta essere sicuri che sia lo strumento giusto per il lavoro.


1
NSOperazione per essere specifica una classe astratta.
Roshan,

3
@Sandy In realtà è il contrario, GCD è usato da NSOperation (almeno nelle versioni successive di iOS e OS X).
Garrettmoon,

1
@BJ Homer Siamo in grado di aggiungere attività nella coda di invio seriale per ottenere la sicurezza. quindi, giustifica il modo in cui la coda operativa ha un vantaggio su questo
Raj Aggrawal,

3
@RajAggrawal Sì, funziona ... ma poi sei bloccato con una coda seriale. NSOperation può fare "eseguire questa operazione dopo che gli altri tre sono stati eseguiti, ma contemporaneamente a tutte le altre cose in corso." Possono esistere dipendenze operative tra operazioni su code diverse. La maggior parte delle persone non ne avrà bisogno, ma se lo fai, NSOperation sarebbe una scelta migliore.
BJ Homer,

369

In linea con la mia risposta a una domanda correlata , non sono d'accordo con BJ e suggerisco di dare prima un'occhiata a GCD su NSOperation / NSOperationQueue, a meno che quest'ultimo non fornisca qualcosa di cui GCD non ha bisogno.

Prima di GCD, ho usato molte NSOperations / NSOperationQueues nelle mie applicazioni per gestire la concorrenza. Tuttavia, da quando ho iniziato a utilizzare GCD su base regolare, ho quasi completamente sostituito NSOperations e NSOperationQueues con blocchi e code di invio. Questo deriva dal modo in cui ho usato entrambe le tecnologie nella pratica e dalla profilazione che ho eseguito su di esse.

Innanzitutto, esiste un importo non banale di spese generali quando si utilizzano NSOperations e NSOperationQueues. Questi sono oggetti di cacao e devono essere allocati e deallocati. In un'applicazione iOS che ho scritto che esegue il rendering di una scena 3D a 60 FPS, stavo usando NSOperations per incapsulare ogni fotogramma renderizzato. Quando ho profilato questo, la creazione e lo smontaggio di queste NSOperations rappresentavano una parte significativa dei cicli della CPU nell'applicazione in esecuzione e rallentavano le cose. Li ho sostituiti con blocchi semplici e una coda seriale GCD, e quell'overhead è scomparso, portando a prestazioni di rendering notevolmente migliori. Questo non è stato l'unico posto in cui ho notato spese generali dall'uso di NSOperations, e l'ho visto sia su Mac che su iOS.

In secondo luogo, c'è un'eleganza al codice di spedizione basato su blocchi che è difficile da abbinare quando si utilizzano NSOperations. È incredibilmente conveniente racchiudere alcune righe di codice in un blocco e inviarlo per eseguirlo su una coda seriale o simultanea, dove la creazione di un NSOperation o NSInvocationOperation personalizzato per fare ciò richiede molto più codice di supporto. So che puoi usare un NSBlockOperation, ma potresti anche inviare qualcosa a GCD. Avvolgere questo codice in blocchi in linea con l'elaborazione correlata nella tua applicazione porta a mio avviso a una migliore organizzazione del codice rispetto a metodi separati o NSOperations personalizzate che incapsulano queste attività.

NSOperations e NSOperationQueues hanno ancora ottimi utilizzi. GCD non ha un vero concetto di dipendenze, in cui NSOperationQueues può impostare grafici di dipendenze piuttosto complessi. Uso NSOperationQueues per questo in una manciata di casi.

Nel complesso, mentre di solito sostengo l'utilizzo del massimo livello di astrazione che compie il compito, questo è un caso in cui sostengo per l'API di livello inferiore di GCD. Tra gli sviluppatori iOS e Mac di cui ho parlato di questo, la stragrande maggioranza sceglie di utilizzare GCD su NSOperations a meno che non stiano prendendo di mira le versioni del sistema operativo senza supporto (quelle precedenti a iOS 4.0 e Snow Leopard).


20
Sono solo leggermente in disaccordo; Uso abbastanza semplicemente GCD. Ma penso che tu abbia scartato troppo NSBlockOperation in questa risposta. Tutti i vantaggi di NSOperationQueue (dipendenze, debugability, ecc.) Si applicano anche alle operazioni di blocco.
BJ Homer,

4
@BJHomer - Penso che l'evitamento di NSBlockOperation sia più una questione di preferenza personale nel mio caso, anche se mi sono allontanato da NSOperations in generale dopo aver visto il sovraccarico dal loro uso trascinare giù un paio di applicazioni. Se ho intenzione di usare i blocchi, tendo ad andare all-in su GCD, con la rara eccezione di quando ho bisogno del supporto per le dipendenze.
Brad Larson

1
+1, grazie per questa analisi. Apple sembra sostenere entrambi (come la sessione del WWDC 2012 sull'interfaccia utente simultanea), quindi questo è molto apprezzato.
Orip,

1
@VolureDarkAngel - GCD è estremamente veloce nel gestire spedizioni del genere. Non dovrebbe essere il tuo collo di bottiglia in una situazione come quella che descrivi, a meno che tu non esegua in qualche modo il backup di una pila di aggiornamenti in una coda a causa di accessi I / O lenti o qualcosa del genere. Questo probabilmente non è il caso qui, però.
Brad Larson

1
@ asma22 - È comune avere calcoli che possono essere eseguiti in blocchi, ma il calcolo finale di uno stadio potrebbe richiedere i risultati di diversi stadi precedenti. In tal caso, è possibile fare in modo che le operazioni successive dipendono dalle operazioni precedenti e la pianificazione sarà gestita in modo tale che tutte siano completate prima dell'esecuzione dell'ultima.
Brad Larson

101

GCDè un'API di basso livello basata su C.
NSOperatione NSOperationQueuesono classi Objective-C.
NSOperationQueueè obiettivo C involucro sopra GCD. Se si utilizza NSOperation, si utilizza implicitamente Grand Central Dispatch.

Vantaggio GCD rispetto a NSOperation:
i. implementazione
Per l' GCDimplementazione è molto leggera,
NSOperationQueuecomplessa e pesante

Vantaggi di NSOperation rispetto a GCD:

io. Control On Operation
è possibile mettere in pausa, annullare, riprendere unNSOperation

ii. Le dipendenze che
è possibile impostare una dipendenza tra due NSOperations
operazioni non verranno avviate fino a quando tutte le dipendenze non verranno restituite vere per il completamento.

iii. Lo stato operativo
può monitorare lo stato di un'operazione o di una coda operazioni. pronto, in esecuzione o finito

iv. Numero massimo di operazioni
è possibile specificare il numero massimo di operazioni in coda che possono essere eseguite contemporaneamente

Quando andare per GCDoNSOperation
quando si desidera un maggiore controllo sull'uso della coda (tutto sopra citato) NSOperation e per i casi semplici in cui si desidera un minor sovraccarico (si desidera solo fare un po 'di lavoro "in background" con pochissimo lavoro aggiuntivo) utilizzareGCD

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


Come detto, il numero massimo di operazioni può essere specificato in NSOperationQueue, quindi quale può essere il numero massimo di operazioni (code di invio) in GCD? Supponiamo di avere un progetto, quindi quante operazioni (code di invio) posso fare. o il loro è un limite massimo che possiamo fare.
Roshan Sah

Dipende dalle condizioni del sistema qui è informazioni dettagliate: stackoverflow.com/questions/14995801/...
Sangram Shivankar

Possiamo annullare l'attività anche in GCD utilizzando DispatchWorkItem e possiamo anche sospendere e riprendere
Ankit garg

@Ankitgarg La chiamata di annullamento su DispatchWorkItem interromperà l'esecuzione delle attività se devono ancora essere eseguite, ma non fermerà qualcosa che è già in esecuzione. e come si mette in pausa / riprende un DispatchWorkItem ??
abhimuralidharan,

34

Un altro motivo per preferire NSOperation a GCD è il meccanismo di annullamento di NSOperation. Ad esempio, un'app come 500px che mostra dozzine di foto, usa NSOperation: possiamo annullare le richieste di celle di immagini invisibili quando scorriamo la vista tabella o la vista raccolta, questo può migliorare notevolmente le prestazioni dell'app e ridurre il footprint di memoria. GCD non può facilmente supportarlo.

Anche con NSOperation, KVO può essere possibile.

Ecco un articolo di Eschaton che vale la pena leggere.


4
Vale la pena notare che se ciò che si sta annullando è l'operazione di rete di caricamento dell'immagine, non è necessario NSOperationper questo, poiché NSURLSessionTask.cancele NSURLSession.invalidateAndCancelfornire questa funzionalità. In generale, NSURLSessionfornisce alcune delle funzionalità di an NSOperationQueue, così come NSURLSessionTaskalcune delle funzionalità di anNSOperation
algal

@algal Come spiegato qui ( stackoverflow.com/questions/21918722/… ), sembra che NSURLSession utilizzi NSOperationQueue come blocco predefinito.
Kalan Nawarathne,

33

GCD è in effetti di livello inferiore rispetto a NSOperationQueue, il suo principale vantaggio è che la sua implementazione è molto leggera e focalizzata su algoritmi e prestazioni senza blocco.

NSOperationQueue fornisce strutture che non sono disponibili in GCD, ma hanno un costo non banale, l'implementazione di NSOperationQueue è complessa e pesante, comporta un sacco di blocchi e utilizza GCD internamente solo in modo molto minimale.

Se hai bisogno delle strutture fornite da NSOperationQueue lo usi sicuramente, ma se GCD è sufficiente per le tue esigenze, ti consiglio di utilizzarlo direttamente per prestazioni migliori, costi di CPU e potenza significativamente inferiori e maggiore flessibilità.


24

Sia NSQueueOperations che GCD consentono di eseguire pesanti attività di calcolo in background su thread separati liberando il battistrada principale dell'applicazione UI.

Bene, in base al post precedente vediamo che NSOperations ha addDependency in modo che tu possa mettere in coda l'operazione una dopo l'altra in sequenza.

Ma ho anche letto delle code seriali GCD che puoi creare esegui le tue operazioni nella coda usando dispatch_queue_create. Ciò consentirà di eseguire una serie di operazioni una dopo l'altra in modo sequenziale.

Vantaggi di NSQueueOperation rispetto a GCD:

  1. Consente di aggiungere dipendenza e consente di rimuovere la dipendenza in modo che per una transazione sia possibile eseguire sequenzialmente utilizzando la dipendenza e per altre transazioni eseguite contemporaneamente mentre GCD non consente l'esecuzione in questo modo.

  2. È facile annullare un'operazione se è in coda e può essere fermata se è in esecuzione.

  3. È possibile definire il numero massimo di operazioni simultanee.

  4. È possibile sospendere l'operazione in cui si trovano in coda

  5. Puoi trovare quante operazioni in sospeso ci sono in coda.


6

GCD è molto facile da usare: se vuoi fare qualcosa in background, tutto ciò che devi fare è scrivere il codice e inviarlo su una coda in background. Fare la stessa cosa con NSOperation richiede molto lavoro aggiuntivo.

Il vantaggio di NSOperation è che (a) hai un oggetto reale a cui puoi inviare messaggi e (b) che puoi annullare una NSOperation. Non è banale. È necessario sottoclassare NSOperation, è necessario scrivere correttamente il codice in modo che la cancellazione e il completamento corretto di un'attività funzionino correttamente. Quindi per cose semplici usi GCD e per cose più complicate crei una sottoclasse di NSOperation. (Esistono sottoclassi NSInvocationOperation e NSBlockOperation, ma tutto ciò che fanno è più semplice con GCD, quindi non c'è motivo di usarle).


3

Bene, NSOperations è semplicemente un'API costruita su Grand Central Dispatch. Quindi, quando usi NSOperations, stai ancora utilizzando Grand Central Dispatch. È solo che NSOperations ti offre alcune fantasiose funzionalità che ti potrebbero piacere. È possibile rendere alcune operazioni dipendenti da altre operazioni, riordinare le code dopo aver sommato gli elementi e altre cose del genere. In effetti, ImageGrabber sta già utilizzando NSOperations e le code delle operazioni! ASIHTTPRequest li usa sotto il cofano e, se lo desideri, puoi configurare la coda delle operazioni che utilizza per comportamenti diversi. Quindi quale dovresti usare? Qualunque abbia senso per la tua app. Per questa app è piuttosto semplice, quindi abbiamo usato direttamente Grand Central Dispatch direttamente, senza bisogno delle fantasiose funzionalità di NSOperation. Ma se ne hai bisogno per la tua app, sentiti libero di usarla!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.