¿Cómo controlar y equilibrar mediante progtwigción un número de subprocesss que la aplicación iOS está ejecutando?

¿Cómo controlar y equilibrar el número de subprocesss que está ejecutando mi aplicación, cómo limitar su número para evitar el locking de la aplicación porque se alcanza el límite de subprocesss?

Aquí en SO vi la siguiente respuesta posible: "La queue concurrente principal (dispatch_get_global_queue) gestiona el número de subprocesss automáticamente" que no me gusta por la siguiente razón:

Considere el siguiente patrón (en mi aplicación real hay ejemplos más simples y más complejos):

dispatch_queue_t defaultBackgroundQueue() { return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); } dispatch_queue_t databaseQueue() { dispatch_queue_create("Database private queue", 0); } dispatch_async(defaultBackgroundQueue(), ^{ [AFNetworkingAsynchronousRequestWithCompletionHandler:^(data){ dispatch_async(databaseQueue(), ^{ // data is about 100-200 elements to parse for (el in data) { } maybe more AFNetworking requests and/or processing in other queues or dispatch_async(dispatch_get_main_queue(), ^{ // At last! We can do something on UI. }); }); }]; }); 

Este layout a menudo conduce a la situación cuando:

  1. La aplicación está bloqueada debido a que se alcanza el límite de hilos (algo así como> 64)
  2. las queues más lentas y por lo tanto estrechas pueden verse abrumadas con una gran cantidad de trabajos pendientes.
  3. el segundo también puede generar un problema de cancelación: si tenemos 100 trabajos esperando la ejecución en una queue de serie, no podemos cancelarlos de una vez.

La solución obvia y tonta sería replace los methods confidenciales de dispatch_async con dispatch_sync, pero definitivamente es el que no me gusta.

¿Cuál es el enfoque recomendado para este tipo de situaciones?

Espero que exista una respuesta más inteligente que solo "Usar NSOperationQueue: puede limitar el número de operaciones simultáneas" (tema similar: Número de subprocesss con NSOperationQueueDefaultMaxConcurrentOperationCount ).

ACTUALIZACIÓN 1: El único patrón decente es ver: es replace todos los dispatch_async's de bloques a queues concurrentes con ejecutar estos bloques envueltos en NSOperations en queues simultáneas basadas en NSOperationQueue con el límite máximo de operaciones establecido (en mi caso también puede establecer un límite máximo de operaciones en la queue basada en NSOperationQueue en la que AFNetworking ejecuta todas sus operaciones).

Está comenzando demasiadas requestes de networking. AFAIK no está documentado en ninguna parte, pero puede ejecutar hasta 6 conexiones de networking simultáneas (que es un número razonable considerando RFC 2616 8.1.4 , párrafo 6). Después de eso, obtienes locking, y GCD compensa la creación de más subprocesss, que por cierto, tienen un espacio de stack de 512 KB cada uno con páginas asignadas a pedido. Entonces, sí, usa NSOperation para esto. Lo utilizo para poner en queue las requestes de networking, boost la prioridad cuando se solicita nuevamente el mismo object, pausar y serializar en el disco si el usuario se va. También superviso la velocidad de las requestes de networking en bytes / time y cambio el número de operaciones simultáneas.

Si bien no veo en su ejemplo dónde exactamente está creando demasiados subprocesss de background, intentaré responder a la pregunta de cómo controlar el número exacto de subprocesss por queue. La documentation de Apple dice:

Las queues simultáneas (también conocidas como un tipo de queue de envío global) ejecutan una o más tareas simultáneamente, pero las tareas aún se inician en el order en que se agregaron a la queue. Las tareas que se ejecutan actualmente se ejecutan en distintos hilos gestionados por la queue de despacho. El número exacto de tareas que se ejecutan en un punto dado es variable y depende de las condiciones del sistema.

Si bien ahora puede (desde iOS5) crear queues simultáneas manualmente, no hay manera de controlar cuántos trabajos se ejecutarán al mismo time por dicha queue. El sistema operativo equilibrará la carga automáticamente. Si, por la razón que sea, no lo desee, podría, por ejemplo, crear un set de n series de queues manualmente y enviar nuevos trabajos a una de sus n queues random:

 NSArray *queues = @[dispatch_queue_create("com.myapp.queue1", 0),dispatch_queue_create("com.myapp.queue2", 0),dispatch_queue_create("com.myapp.queue3", 0)]; NSUInteger randQueue = arc4random() % [queues count]; dispatch_async([queues objectAtIndex:randQueue], ^{ NSLog(@"Do something"); }); randQueue = arc4random() % [queues count]; dispatch_async([queues objectAtIndex:randQueue], ^{ NSLog(@"Do something else"); }); 

No estoy de acuerdo con este layout, creo que las queues simultáneas son bastante buenas para equilibrar los resources del sistema. Pero desde que me preguntaste, creo que es un enfoque factible.