NSOperation vs Grand Central Dispatch


465

Estoy aprendiendo sobre programación concurrente para iOS. Hasta ahora he leído sobre NSOperation/NSOperationQueue y GCD. ¿Cuáles son las razones para usar NSOperationQueueover GCDy viceversa?

Suena como ambos GCDy NSOperationQueueabstrae la creación explícita NSThreadsdel usuario. Sin embargo, la relación entre los dos enfoques no está clara para mí, por lo que cualquier comentario será apreciado.


10
+1 para una buena pregunta: curiosidad por los resultados. Hasta ahora, acabo de leer que GCD se puede enviar fácilmente a través de núcleos de CPU, convirtiéndolo en la "nueva mierda caliente".
Hasta el

3

Respuestas:


517

GCDes una API de bajo nivel basada en C que permite el uso muy simple de un modelo de concurrencia basado en tareas. NSOperationy NSOperationQueueson clases de Objective-C que hacen algo similar. NSOperationse introdujo primero, pero a partir de 10.5 y iOS 2 , NSOperationQueuey los amigos se implementan internamente usando GCD.

En general, debe usar el nivel más alto de abstracción que se adapte a sus necesidades. Esto significa que generalmente debe usar en NSOperationQueuelugar de GCD, a menos que necesite hacer algo que NSOperationQueueno sea compatible.

Tenga en cuenta que NSOperationQueueno es una versión "tonta" de GCD; de hecho, hay muchas cosas que puedes hacer de manera muy simple NSOperationQueueque requieren mucho trabajo con pure GCD. (Ejemplos: colas restringidas de ancho de banda que solo ejecutan N operaciones a la vez; establecer dependencias entre operaciones. Ambas muy simples con NSOperation, muy difíciles con GCD.) Apple ha hecho el trabajo duro de aprovechar GCD para crear una API amigable con los objetos muy agradable NSOperation. Aproveche su trabajo a menos que tenga una razón para no hacerlo.

Advertencia : Por otro lado, si realmente solo necesita enviar un bloque y no necesita ninguna de las funciones adicionales que NSOperationQueueproporciona, no hay nada de malo en usar GCD. Solo asegúrese de que sea la herramienta adecuada para el trabajo.


1
NSOperation para ser específico una clase abstracta.
Roshan

3
@Sandy En realidad es lo contrario, GCD es utilizado por NSOperation (al menos en versiones posteriores de iOS y OS X).
garrettmoon

1
@BJ Homer Podemos agregar tareas en la cola de despacho en serie para lograr dependencia. así que justifique cómo la cola de operaciones tiene ventaja sobre eso
Raj Aggrawal

3
@RajAggrawal Sí, eso funciona ... pero luego estás atrapado en una cola en serie. NSOperation puede hacer "ejecutar esta operación después de que los otros tres hayan terminado, pero al mismo tiempo que todo lo demás está sucediendo". Las dependencias de operación pueden existir incluso entre operaciones en diferentes colas. La mayoría de las personas no necesitarán eso, pero si lo hace, NSOperation sería una mejor opción.
BJ Homer

369

En línea con mi respuesta a una pregunta relacionada , voy a estar en desacuerdo con BJ y sugerirle que primero mire GCD sobre NSOperation / NSOperationQueue, a menos que este último proporcione algo que necesita que GCD no.

Antes de GCD, utilicé muchas NSOperations / NSOperationQueues dentro de mis aplicaciones para gestionar la concurrencia. Sin embargo, desde que comencé a usar GCD de forma regular, he reemplazado casi por completo NSOperations y NSOperationQueues con bloques y colas de despacho. Esto ha venido de cómo he usado ambas tecnologías en la práctica, y del perfil que he realizado en ellas.

Primero, hay una cantidad de sobrecarga no trivial cuando se usan NSOperations y NSOperationQueues. Estos son objetos Cocoa, y deben asignarse y desasignarse. En una aplicación para iOS que escribí que renderiza una escena tridimensional a 60 FPS, estaba usando NSOperations para encapsular cada cuadro renderizado. Cuando hice un perfil de esto, la creación y el desmantelamiento de estas operaciones de NSO representaban una parte significativa de los ciclos de la CPU en la aplicación en ejecución y ralentizaban las cosas. Los reemplacé con bloques simples y una cola serial GCD, y esa sobrecarga desapareció, lo que condujo a un rendimiento de representación notablemente mejor. Este no fue el único lugar donde noté gastos generales al usar NSOperations, y lo he visto tanto en Mac como en iOS.

En segundo lugar, hay una elegancia en el código de envío basado en bloques que es difícil de igualar cuando se usan NSOperations. Es increíblemente conveniente envolver unas pocas líneas de código en un bloque y enviarlo para que se realice en una cola serial o concurrente, donde la creación de una NSOperation o NSInvocationOperation personalizada para hacer esto requiere mucho más código de soporte. Sé que puedes usar una NSBlockOperation, pero también podrías enviar algo a GCD. Envolver este código en bloques en línea con el procesamiento relacionado en su aplicación conduce, en mi opinión, a una mejor organización del código que tener métodos separados o operaciones NSO personalizadas que encapsulan estas tareas.

NSOperations y NSOperationQueues todavía tienen muy buenos usos. GCD no tiene un concepto real de dependencias, donde NSOperationQueues puede configurar gráficos de dependencia bastante complejos. Utilizo NSOperationQueues para esto en un puñado de casos.

En general, aunque generalmente defiendo el uso del más alto nivel de abstracción que realiza la tarea, este es un caso en el que defiendo la API de nivel inferior de GCD. Entre los desarrolladores de iOS y Mac con los que he hablado sobre esto, la gran mayoría opta por usar GCD sobre NSOperations a menos que estén dirigidos a versiones de SO sin soporte para ellas (anteriores a iOS 4.0 y Snow Leopard).


20
Solo estoy ligeramente en desacuerdo; Yo uso bastante GCD bastante. Pero creo que descontas demasiado NSBlockOperation en esta respuesta. Todos los beneficios de NSOperationQueue (dependencias, debugability, etc.) también se aplican a las operaciones de bloqueo.
BJ Homer

44
@BJHomer: creo que evitar NSBlockOperation es más una cuestión de preferencia personal en mi caso, aunque he evitado las NSOperations en general después de ver que los gastos generales de su uso arrastran un par de aplicaciones. Si voy a usar bloques, tiendo a usar todo en GCD, con la rara excepción de cuando necesito soporte de dependencia.
Brad Larson

1
+1, gracias por este análisis. Apple parece estar abogando por ambos (como la sesión de WWDC 2012 sobre IU concurrente), por lo que esto es muy apreciado.
orip

1
@VolureDarkAngel: GCD es extremadamente rápido en el manejo de despachos como ese. No debería ser su cuello de botella en una situación como la que describe, a menos que de alguna manera haga una copia de seguridad de una pila de actualizaciones en una cola debido a los lentos accesos de E / S o algo por el estilo. Sin embargo, probablemente ese no sea el caso aquí.
Brad Larson

1
@ asma22: es común tener cálculos que se pueden hacer en trozos, pero el cálculo final de una etapa puede necesitar los resultados de varias etapas anteriores. En ese caso, puede hacer que la operación posterior dependa de las operaciones anteriores, y la programación se administrará de manera que todas se completen antes de que se ejecute la última.
Brad Larson

101

GCDes una API basada en C de bajo nivel.
NSOperationy NSOperationQueueson clases de Objective-C.
NSOperationQueuees el envoltorio objetivo C terminado GCD. Si está utilizando NSOperation, está utilizando implícitamente Grand Central Dispatch.

Ventaja de GCD sobre NSOperation:
i. implementación
Para la GCDimplementación es muy ligero,
NSOperationQueuees complejo y pesado

Ventajas de NSOperation sobre GCD:

yo. Control en funcionamiento
puede pausar, cancelar, reanudar unNSOperation

ii. Las dependencias en las
que puede configurar una dependencia entre dos NSOperations
operaciones no se iniciarán hasta que todas sus dependencias vuelvan verdaderas para finalizar.

iii) El estado de operación
puede monitorear el estado de una operación o una cola de operaciones. listo, ejecutándose o terminado

iv. Número máximo de operaciones
: puede especificar el número máximo de operaciones en cola que pueden ejecutarse simultáneamente

Cuándo ir GCDoNSOperation
cuándo desea tener más control sobre el uso de la cola (todo lo mencionado anteriormente) NSOperation y para casos simples en los que desea menos sobrecarga (solo desea hacer un trabajo "en segundo plano" con muy poco trabajo adicional)GCD

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


Como se dijo, el número máximo de operaciones se puede especificar en NSOperationQueue, entonces, ¿cuál puede ser el número máximo de operaciones (colas de despacho) en GCD? Supongamos que tengo un proyecto, entonces cuántas operaciones (colas de despacho) puedo hacer. o hay límites máximos hasta los cuales podemos hacer.
Roshan Sah

Depende de las condiciones del sistema aquí hay información detallada: stackoverflow.com/questions/14995801/…
Sangram Shivankar

También podemos cancelar la tarea en GCD usando DispatchWorkItem y también podemos suspenderla y reanudarla
Ankit garg

@Ankitgarg La cancelación de llamadas en DispatchWorkItem detendrá la ejecución de tareas si aún no se han ejecutado, pero no detendrá algo que ya se está ejecutando. y cómo pausar / reanudar un DispatchWorkItem ??
abhimuralidharan

34

Otra razón para preferir NSOperation sobre GCD es el mecanismo de cancelación de NSOperation. Por ejemplo, una aplicación como 500px que muestra docenas de fotos, usa NSOperation, podemos cancelar las solicitudes de celdas de imagen invisibles cuando desplazamos la vista de tabla o vista de colección, esto puede mejorar en gran medida el rendimiento de la aplicación y reducir la huella de memoria. GCD no puede soportar esto fácilmente.

También con NSOperation, KVO puede ser posible.

Aquí hay un artículo de Eschaton que vale la pena leer.


44
Vale la pena señalar que si lo va a cancelar es la operación de la red de cargar la imagen, entonces no es necesario NSOperationpara esto, como NSURLSessionTask.cancely NSURLSession.invalidateAndCancelproporcionar esta funcionalidad. En general, NSURLSessionproporciona parte de la funcionalidad de un NSOperationQueue, como NSURLSessionTaskproporciona parte de la funcionalidad de unNSOperation
algal

@algal Como se explica aquí ( stackoverflow.com/questions/21918722/… ), parece que NSURLSession usa NSOperationQueue como un bloque de construcción.
kalan nawarathne

33

GCD es de hecho un nivel más bajo que NSOperationQueue, su principal ventaja es que su implementación es muy liviana y se enfoca en algoritmos y rendimiento sin bloqueo.

NSOperationQueue proporciona instalaciones que no están disponibles en GCD, pero tienen un costo no trivial, la implementación de NSOperationQueue es compleja y pesada, implica mucho bloqueo y usa GCD internamente solo de manera mínima.

Si necesita las facilidades proporcionadas por NSOperationQueue, utilícelo por todos los medios, pero si GCD es suficiente para sus necesidades, recomendaría usarlo directamente para un mejor rendimiento, un costo de CPU y de energía significativamente menor y más flexibilidad.


24

Tanto NSQueueOperations como GCD permiten ejecutar tareas de cálculo pesadas en segundo plano en subprocesos separados al liberar la banda de rodadura principal de la aplicación UI.

Bueno, según la publicación anterior, vemos que NSOperations tiene addDependency para que pueda poner en cola su operación una tras otra secuencialmente.

Pero también leí sobre las colas en serie GCD que puede crear, ejecute sus operaciones en la cola usando dispatch_queue_create. Esto permitirá ejecutar un conjunto de operaciones una tras otra de manera secuencial.

Ventajas de NSQueueOperation sobre GCD:

  1. Permite agregar dependencia y le permite eliminar la dependencia, por lo que para una transacción puede ejecutar secuencialmente usando dependencia y para otra transacción que se ejecuta simultáneamente, mientras que GCD no permite ejecutar de esta manera.

  2. Es fácil cancelar una operación si está en la cola, puede detenerse si se está ejecutando.

  3. Puede definir el número máximo de operaciones concurrentes.

  4. Puede suspender la operación que están en la cola

  5. Puede encontrar cuántas operaciones pendientes hay en la cola.


6

GCD es muy fácil de usar: si desea hacer algo en segundo plano, todo lo que necesita hacer es escribir el código y enviarlo en una cola en segundo plano. Hacer lo mismo con NSOperation es mucho trabajo adicional.

La ventaja de NSOperation es que (a) tiene un objeto real al que puede enviar mensajes, y (b) que puede cancelar una NSOperation. Eso no es trivial. Debe subclasificar NSOperation, debe escribir su código correctamente para que la cancelación y la finalización correcta de una tarea funcionen correctamente. Entonces, para cosas simples, usa GCD, y para cosas más complicadas, crea una subclase de NSOperation. (Hay subclases NSInvocationOperation y NSBlockOperation, pero todo lo que hacen es más fácil con GCD, por lo que no hay una buena razón para usarlas).


3

Bueno, NSOperations es simplemente una API construida sobre Grand Central Dispatch. Entonces, cuando está usando NSOperations, todavía está usando Grand Central Dispatch. Es solo que NSOperations le brinda algunas características sofisticadas que podrían gustarle. Puede hacer que algunas operaciones dependan de otras operaciones, reordenar las colas después de sumar elementos, y otras cosas por el estilo. De hecho, ImageGrabber ya está utilizando NSOperations y colas de operaciones. ASIHTTPRequest los usa bajo el capó, y puede configurar la cola de operaciones que usa para diferentes comportamientos si lo desea. Entonces, ¿cuál deberías usar? Lo que tenga sentido para su aplicación. Para esta aplicación es bastante simple, por lo que solo utilizamos Grand Central Dispatch directamente, sin necesidad de las características sofisticadas de NSOperation. Pero si los necesita para su aplicación, ¡no dude en usarla!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.