Tiempo y performance de ejecución del process utilizando varias queues de despacho y NSOperationQueue

Tengo un XML en mi package de aplicaciones. Estoy parsing este file XML. NSXMLParser este XML usando NSXMLParser y usando las siguientes forms:

  1. ejecutando todo el código en serie en el hilo principal
  2. Uso de queues de despacho (GCD):

    2.1 Crear mi propia queue de despacho utilizando dispatch_queue_create

    2.2 utilizando una queue global con alta prioridad dispatch_get_global_queue

    2.3 utilizando una queue global con baja prioridad

    2.4 utilizando una queue global con prioridad de background

  3. usando NSOperationQueue

Comprobé el performance y el time total que se tomó al ejecutar el análisis del file XML y encontré resultados realmente extraños (o pueden ser correctos).

Los siguientes son los códigos para las forms analizadas anteriormente:

  1. Ejecución en serie en el hilo principal – Tiempo de ejecución 34 mseg.

     BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error]; if (success) { DLog(@"Parsing Complete"); } else DLog(@"Parse error %@",[error description]); 

2.1 Usando dispatch_queue_create – Tiempo de ejecución 68 mseg .

 dispatch_queue_t backgroundQueue = dispatch_queue_create("BackQueue", NULL); dispatch_async(backgroundQueue, ^{ NSError *error = nil; BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error]; if (success) { DLog(@"Parsing Complete"); } else DLog(@"Parse error %@",[error description]); }); dispatch_release(backgroundQueue); 

2.2 utilizando la queue global con alta prioridad dispatch_get_global_queue – Tiempo de ejecución: 74 mseg

 dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_async(backgroundQueue, ^{ NSError *error = nil; BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error]; if (success) { DLog(@"Parsing Complete"); } else DLog(@"Parse error %@",[error description]); }); dispatch_release(backgroundQueue); 

2.3 Del mismo modo que 2.2 Uso de queue global con prioridad BAJA DISPATCH_QUEUE_PRIORITY_LOWTiempo de ejecución – 72 mseg

2.4 Del mismo modo que 2.2 Uso de queue global con FONDO Prioridad DISPATCH_QUEUE_PRIORITY_BACKGROUNDTiempo de ejecución: 37 mseg

2.5. Uso de NSOperationQueue (subsorting de NSOperation) – Tiempo de ejecución: 36 mseg

¿Alguien puede ayudarme a descubrir estos times de ejecución y por qué son tan extraños (o me estoy perdiendo algo)? ¿Por qué obtengo el mejor performance con el método 1. ¿Por qué DISPATCH_QUEUE_PRIORITY_BACKGROUND ofrece un mejor performance que HIGH? ¿Por qué NSOperationQueue da mejores resultados que GCD?

Actualizar:

Probé varias queues de envío y operación para dos escenarios:

  1. Invoque un solo trabajo que analice repetidamente un file XML grande (725kb) 100 veces en una sola operación; y

  2. Cola 100 operaciones para analizar el mismo file XML muy grande una vez cada uno.

Mis resultados (medidos en segundos) en mi iPhone 5 fueron los siguientes:

  1. Para el primer escenario:

     Cola principal: 18.7
     NSOperation: 18.4
     Cola global de alta prioridad: 18.3
     Cola global de prioridad pnetworkingeterminada: 18.4
     Cola de baja prioridad global: 18.4
     Cola de background global: 18.5
     Cola de envío en serie: 18.3
    
  2. Para mi segundo escenario:

     Cola principal: 18.7
     NSOperation: 10.9
     Fila global de alta prioridad: 10.9
     Cola de prioridad pnetworkingeterminada global: 10.8
     Cola de baja prioridad global: 10.8
     Cola de background global: 11.0
     Cola de envío en serie: 18.5
    

Entonces extraigo dos conclusiones bastante sorprendentes de esto:

  • Para una operación de segundo plano informatizada intensiva como mínimo, no parece haber mucha variación entre las diversas técnicas de background concurrentes;

  • Al dividir una tarea en múltiples operaciones, las operaciones en segundo plano concurrentes ( NSOperationQueue , GCD global queues) gozaron de una ventaja de performance sobre las operaciones en serie.

No sugiero, sin embargo, que un dispositivo bajo contención de resources no muestre un comportamiento diferente en términos de progtwigción (en particular, los types de queue globales de GCD, ver dispatch_queue_priority_t , afectarían la progtwigción de las operaciones con otras operaciones simultáneas en queue en el dispositivo). Solo trato de demostrar empíricamente que las diversas queues no son significativamente más o less eficientes que las demás. Dicho esto, personalmente no utilizaría DISPATCH_QUEUE_PRIORITY_HIGH en mis aplicaciones, ya que supongo que tendría la posibilidad de afectar la funcionalidad central de iOS.

Además, en aras de una divulgación completa, debo admitir que me estoy centrando en las diferencias en el performance material. Es muy posible que un mecanismo u otro pueda ofrecer diferencias de performance medidas en mseg. Cuando estoy considerando diferentes enfoques para el performance de background, definitivamente estoy más centrado en las diferencias de performance observables por el usuario.


Respuesta original:

parseManyTimes mi parseManyTimes (que analiza repetidamente un file XML grande) de la queue principal:

 [self parseManyTimes:@"Main queue"]; 

Via NSOperation :

 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ [self parseManyTimes:@"NSOperation"]; }]; queue = nil; 

A través de queues globales en GCD:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_DEFAULT"]; }); 

y

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_HIGH"]; }); 

y

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_LOW"]; }); 

y a través de una queue serie GCD:

 dispatch_queue_t dispatchQueue = dispatch_queue_create("org.rob.test", NULL); dispatch_async(dispatchQueue, ^{ [self parseManyTimes:@"dispatch_queue_create"]; }); 

y los resultados no difirieron significativamente entre sí (todos entre 32.2 y 32.5 segundos cada uno). Mi rutina de análisis es:

 - (void)parseManyTimes:(NSString *)type { NSDate *startDate = [NSDate date]; for (NSInteger i = 0; i < 100; i++) [self parse]; NSLog(@"%@: %.1f", type, [[NSDate date] timeIntervalSinceDate:startDate]); } - (void)parse { NSURL *url = [[NSBundle mainBundle] URLForResource:@"personnel" withExtension:@"xml"]; NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url]; parser.delegate = self; [parser parse]; } 

Corrí esto en un iPad en un file XML de 725 kb. Claramente, la forma en que estructuré esto, con un process que consume mucho time, tenderá a tener una variación insignificante en la forma en que se envían las diferentes queues, sino que se centran en la operación de background. Por eso no plantea ninguna preocupación (al less para mí) en los problemas de performance material en las diversas técnicas.

Los resultados fueron:

 Cola principal: 32.3
 NSOperation: 32.2
 DISPATCH_QUEUE_PRIORITY_DEFAULT: 32.4
 DISPATCH_QUEUE_PRIORITY_HIGH: 32.3
 DISPATCH_QUEUE_PRIORITY_LOW: 32.5
 dispatch_queue_create: 32.3

El performance de varias queues simultáneas pnetworkingeterminadas es solo relativo. La prioridad "alta" solo significa más alta que las otras queues. Espero que para su punto de reference sintético no haya ocurrido más en ese momento, por lo que todas las queues parecen funcionar de manera equivalente. Si desea una demostración real de la ponderación, encoje cien operaciones de análisis a cada una de las queues concurrentes, de una vez, y compare sus times de ejecución.

Tenga en count también que NSOperation utiliza la queue simultánea de prioridad pnetworkingeterminada para ejecutar, por lo que vio que el performance es esencialmente el mismo. En el mejor de los casos, solo está midiendo la sobrecarga de NSOperation, que es pequeña.

En sus resultados iniciales, vio times muy diferentes. ¿Cuáles fueron las condiciones de esas mediciones? Por ejemplo, si está realizando esto al inicio de la aplicación, cambiar el análisis XML a otro subprocess o queue podría hacer que le tome más time, ya que su subprocess principal y su queue podrían competir con ella por el time de la CPU. Una mejor testing en ese tipo de caso sería el time de lanzamiento general, lo que demostrará el beneficio de utilizar varios núcleos.