tutorials tutorial example objective-c ios multithreading concurrency grand-central-dispatch

objective c - tutorial - ¿Cuáles son las diferentes maneras de llamar a mi método en un hilo separado?



nsoperationqueue swift 3 example (2)

Aquí hay una respuesta actualizada a esta vieja pregunta. Las operaciones NSO se implementan con libdispatch tanto para macos como para ios ahora. Lo han estado por algún tiempo. La forma preferida de llamar a un hilo diferente es con libdispatch o NSOperations. La idea principal a tener en cuenta es "Calidad de servicio" o "QOS". Una QOS es algo asignado a un subproceso, y cuando lo asigna a una cola de envío, y NSOperationQueue, o una NSOperation, básicamente dice: "Quiero que esto se ejecute en un subproceso con esta QOS asignada". El caso especial es el hilo principal.

Puede que todavía haya algunos casos para usar NSThread, pero no he tenido ninguno por mucho tiempo.

Tengo algún método de cálculo de datos (que sea "myMethod:"), y quiero mover la llamada a otro hilo porque no quiero bloquear la funcionalidad de mi interfaz de usuario principal. Entonces, comencé a investigar un poco sobre cómo llamar a mi método en otro hilo. Por lo que veo, actualmente, hay muchas maneras diferentes de hacerlo. Aquí hay una lista:

a) usando hilos puros (disponibles desde iOS 2.0):

[NSThread detachNewThreadSelector:@selector(myMethod:) toTarget:self withObject:_myParamsArray];

b) utilizando un atajo simple (disponible desde iOS 2.0). Disponible desde NSObject heredado pero el método pertenece a la clase NSThread también:

[self performSelectorInBackground:@selector(myMethod:) withObject:_myParamsArray];

c) utilizando un nuevo enfoque de las colas de Grand Central Dispatch (disponible desde iOS 4.0):

dispatch_async(dispatch_get_global_queue(0, 0), ^ { [self myMethod:_myParamsArray]; });

d) de alguna manera, usando algunas clases como NSOperation, NSBlockOperation o NSOperationQueue, aunque no estoy seguro de cómo hacerlo exactamente (se agradecería algún ejemplo)

Actualmente, he usado el caso "b", pero tengo curiosidad acerca de los pros y los contras y otras sugerencias relacionadas con eso.

ACTUALIZACIÓN: e) también se encontró otra forma de realizar tareas de subprocesamiento similares: ejecutar bucles . Aquí hay un extracto de Apple Docs:

Un ciclo de ejecución es un ciclo de procesamiento de eventos que se usa para programar el trabajo y coordinar la recepción de eventos entrantes. El propósito de un bucle de ejecución es mantener el hilo ocupado cuando hay trabajo por hacer y poner el hilo en suspensión cuando no hay ninguno.

En mi humilde opinión, más o menos estás lidiando con la misma tarea: cómo llamar a tu método en un hilo separado para su operación asíncrona.

ACTUALIZACIÓN2: Ya tenía algo de experiencia con NSInvocationOperation y NSOperationQueue y IMHO es bastante conveniente. De acuerdo con los documentos de Apple, las operaciones GCD y NSO son una forma preferida de implementar subprocesos múltiples. Y también, NSOperations se ejecuta en GCD a partir de iOS 4.0. En resumen, crea una instancia de NSIvocationOperation (como una llamada a su método), luego crea una instancia de NSOperationQueue y agrega invocación a la cola. NSOperationQueue es lo suficientemente inteligente, puede instanciar múltiples objetos NSIvocationOperation (envolviendo sus llamadas a métodos) y colocarlos en NSOperationQueue. El resto está asegurado. NSOperationQueue determina la cantidad de subprocesos paralelos que necesita para realizar las llamadas (NSInvocationOperation) y lo maneja por usted. Puede ejecutar la primera llamada en el subproceso A, luego la segunda en el subproceso B, la tercera en el subproceso C y luego en el subproceso B, así que no tiene que preocuparse por eso. Pero si lo desea, puede saber cómo pueden utilizar los subprocesos máximos NSOperationQueue para realizar llamadas (por ejemplo 1) pero no tengo necesidad de hacerlo. De forma predeterminada, todas las tareas se realizan en un hilo diferente al principal, por lo que las colas de operaciones son asíncronas de forma predeterminada. Además, si desea realizar sus llamadas de método (cada una envuelta en NSInvocationOperation) en una cola estricta, puede agregar dependencias y, por lo tanto, NSOperationQueue conservará el orden de llamada del método. Aquí hay un ejemplo:

// wrap your method call into NSInvocationOperation object NSInvocationOperation *currentOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(yourMethodCall) object:nil]; // _sharedOperationQueue is a shared NSOperationQueue // get all executing operations from the queue and get the last operation _lastOperation = [[_sharedOperationQueue operations] lastObject]; // check if _lastOperation is not nil if (_lastOperation) { // if not then add dependency, so the calls would be performed in a queue [currentOperation addDependency:_lastOperation]; } // say - execute my method (operation) [_sharedOperationQueue addOperation:currentOperation]; _lastOperation = currentOperation; // mark as last operation for adding dependency to the next operation // the queue will retain invocation operation so you will release [currentOperation release]; ..... you can create another NSInvocationOperation and add it to the queue....

En cuanto a RUNLOOPs, aún así, a veces los enfrentará, por ejemplo, al iniciar / programar un temporizador o al hacer conexiones NSURL. En mi humilde opinión, un runloop podría compararse con una cola de tareas ejecutadas en un hilo. En mi humilde opinión, un runloop es un puntero a un hilo que funciona como una cola: tiene tareas que podrían generar eventos y se colocarán al final de la cola en ese hilo. Por defecto, todas las tareas en su aplicación se ejecutan en un solo runloop, en un solo hilo. Estoy diciendo que es un puntero porque cuando su aplicación genera eventos, la aplicación debe saber dónde colocar ese evento (evento de toque u otra devolución de llamada de delegado) para su ejecución. Por supuesto, deberías leer sobre runloops para obtener información más detallada porque estos son solo mis pensamientos.


Por lo general, preferiría el enfoque GCD.

Es más simple cuando se trata de sincronización / bloqueo que los hilos puros (NSThread - pthread), y puede ser más preciso en una perspectiva de rendimiento.

Al usar subprocesos puros, el problema es que puede tener problemas de rendimiento, dependiendo de la cantidad de núcleos / procesadores disponibles.

Por ejemplo, si solo tiene un núcleo, la creación de muchos subprocesos puede ralentizar su aplicación, ya que la CPU pasará la mayor parte del tiempo cambiando de un subproceso a otro, guardando la pila, los registros, etc.

Por otro lado, si tiene muchos núcleos disponibles, puede ser bueno crear muchos hilos diferentes.

Aquí es donde GCD ayuda, ya que administra esto por ti. Creará la cantidad adecuada de hilos, en función de los recursos disponibles del sistema, para garantizar una utilización óptima y programar sus acciones de manera adecuada.

Sin embargo, por ese motivo, las tareas iniciadas con GCD pueden no ser en tiempo real.

Por lo tanto, si REALMENTE necesita que una tarea separada se ejecute inmediatamente, use un subproceso explícito. De lo contrario, utilice GCD.

Espero que esto te ayudará : )

EDITAR

Una nota sobre performSelectorInBackground : simplemente crea un nuevo hilo. Así que básicamente no hay diferencia con el enfoque NSThread.

EDIT 2

Las cosas relacionadas con NSOperation son un poco diferentes. En Mac OS X, se implementan utilizando GCD desde la versión 10.6. Las versiones anteriores utilizan hilos.

En iOS, se implementan utilizando solo hilos.

Referencia

Todo esto está muy bien explicado en la Guía de programación de concurrencia . Discute los enfoques de GCD y de subprocesos, con muchos detalles sobre los usos e implementaciones.

Si no lo has leído ya, deberías echarle un vistazo.