2012-06-08 8 views
14

¿Es posible utilizar un objeto NSoperationQueue como una cola FIFO en serie estableciendo su maxConcurrentOperationCount en 1?NSOperationQueue cola FIFO en serie

observo que el estado docs ...

Para una cola cuyo número máximo de operaciones simultáneas se pone a 1, esto equivale a una cola de serie. Sin embargo, nunca debe confiar en la ejecución en serie de los objetos de operación.

¿Esto significa que la ejecución FIFO no está garantizada?

Respuesta

23

En la mayoría de los casos, será FIFO. Sin embargo, puede configurar dependencias entre NSOperations de modo que una operación enviada antes permita que otras operaciones la pasen en la cola hasta que se satisfagan sus dependencias.

Esta gestión de la dependencia es la razón por la que los documentos indican que no se puede garantizar FIFO-ness. Sin embargo, si no está utilizando dependencias, debería estar seguro de que puede confiar en ello.

actualización: NSOperation también tiene una propiedad queuePriority, que también puede causar operaciones a ejecutar con el fin de no FIFO. La operación de mayor prioridad sin dependencias pendientes siempre se ejecutará primero.

Una subclase NSOperation también puede anular -isReady, lo que podría hacer que retroceda en la cola.

Así que la ejecución en su cola está garantizada como serie, ya que no se ejecutará más de una operación a la vez en esta cola. Pero Apple no puede garantizar FIFO; eso depende de lo que está haciendo con las operaciones que ponen en

+0

Orden de ejecución también depende de la prioridad de la cola de la operación. – JeremyP

+0

Muy cierto. Actualizado. –

+0

Entonces, si todas mis operaciones tienen la misma prioridad, no tienen dependencias y dependen solo de la implementación de la superclase de 'isReady' (no anulo), ¿debería dar como resultado una cola FIFO? – Barjavel

-2

Para realizar una FIFO simple usando nsInvocationopration Usted tendrá que establecer una operación que se dependía de la otra Usando addDependency:. Método

NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
NSInvocationOperation *oper1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"1"]; 

NSInvocationOperation *oper2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"2"]; 
NSInvocationOperation *oper3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"3"]; 

[oper2 addDependency:oper1]; 
[oper3 addDependency:oper2]; 
//oper3 depends on oper2 wich depends on oper1 
//order of execution will ber oper1->oper2->oper3 

//Changing the oreder will not change the result 
[queue addOperation:oper2]; 
[queue addOperation:oper3]; 
[queue addOperation:oper1]; 


- (void) doSth:(NSString*)str 
{ 
    NSLog(str); //log will be 1 2 3 
    //When you remove the addDependency calls, the logging result that i got where 
    //different between consecutive runs i got the following 
    //NSLog(str); //log will be 2 1 3 
    //NSLog(str); //log will be 3 1 2 
} 

Nota: si está utilizando NSInvocationOperation y después colocar el maxConcurrentOperationCount a 1 dé más probable es que el truco para usted, ya isReady no será editable por usted

Pero maxConcurrentOperationCount = 1 no sería una buena solución si estás planeando crear sus propias subclases de NSOperation

Dado que en los derivados NSOperation que podría reemplazar la función isReady y volver no, (imagina alguna operación que tenga que esperar algunos datos de un servidor a fin de funcionar correctamente) en estos casos que volvería isReady no hasta que esté realmente listo en estos casos se tendrá que añadir dependencies entre operations dentro de la cola de

a partir de documentos de manzana , equivale a una cola de serie . Sin embargo, nunca debe confiar en la ejecución en serie de los objetos de operación. Los cambios en la preparación de una operación pueden cambiar el orden de ejecución resultante

+0

¿Puede explicar por qué las dependencias son necesarias? –

+0

@BJHomer he actualizado mi respuesta para incluir un poco de registro –

+0

Su cola en el ejemplo no tiene 'maxConcurrentOperationCount = 1' como el OP especificado. ¿Esto todavía sucede con ese conjunto? –

12

La cola no es FIFO como se menciona en la documentación.Puede hacer que sea estrictamente FIFO si se asegura de que cualquier operación nueva dependa de la última operación agregada en la cola y de que solo puede ejecutar una sola operación a la vez. Omar solución es correcta, pero de manera más general, se puede hacer lo siguiente:

NSOperationQueue* queue = [[ NSOperationQueue alloc ] init]; 
queue.maxConcurrentOperationCount = 1; 

NSOperation* someOperation = [ NSBlockOperation blockOperationWithBlock:^(void) { NSLog(@"Done.");} ]; 

if (queue.operations.count != 0) 
    [ someOperation addDependency: queue.operations.lastObject ]; 

Esto funciona porque queue.operations es una matriz: lo que se agrega no se reordena (que no es un NSSet por ejemplo). También puede simplemente añadir una categoría a su NSOperationQueue:

@interface NSOperationQueue (FIFOQueue) 
- (void) addOperationAfterLast:(NSOperation *)op; 
@end 

@implementation NSOperationQueue (FIFOQueue) 

- (void) addOperationAfterLast:(NSOperation *)op 
{ 
    if (self.maxConcurrentOperationCount != 1) 
     self.maxConcurrentOperationCount = 1; 

    NSOperation* lastOp = self.operations.lastObject; 
    if (lastOp != nil) 
     [ op addDependency: lastOp ]; 

    [ self addOperation:op]; 
} 

@end 

y utilice [cola de addOperationAfterLast: myOperation]. queuePriority no tiene nada que ver con FIFO, está relacionado con la programación de trabajos.

Editar: después de un comentario a continuación, suspender la cola si se busca el conteo tampoco es suficiente. Creo que esta forma está bien (después de las pruebas, esto no crea una condición de carrera y no falla).

Algo de información: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperationQueue_class/#//apple_ref/occ/instp/NSOperationQueue/suspended

+0

Hay un problema con este tipo de solución. Lo he estado usando Ocasionalmente, el último objeto de la cola desaparecerá después de la verificación en queue.operations.count. Es raro, pero sucede. Y no estoy seguro de cómo resolverlo. –

+0

Buen punto No vi eso, pero sí: si operations.count está marcado mientras se ejecuta la cola, puede terminar mientras estamos ingresando la condición if. Creo que el formulario editado es mejor y más seguro: (las pruebas aquí no se bloquean, aunque un intento de suspender la cola no funciona (no se muestra)). – Daniel

+0

Esa es la solución a la que también recurrí; crea una variable local, evitando que se libere la NSOperation. –

Cuestiones relacionadas