NSOperation waitUntilFinished ждет долго - PullRequest
0 голосов
/ 06 января 2012

Я использую подкласс NSOperation (называемый PointsOperation) для выполнения некоторых вычислений в фоновом режиме в моем приложении.Из-за поведения пользователя эти вычисления могут быть отменены, и начались новые вычисления.В этом случае я создам новый экземпляр PointsOperation и добавлю его к тому же NSOperationQueue, что и первый.Первым делом в основном методе PointsOperation он проверит, запущена ли другая операция, и отменит ее.

Поскольку операции используют некоторые общие кэши, они не могут (и не нужны).быть) работает параллельно.Поэтому вторая операция будет ждать, пока первая не завершится.Результирующий код для метода main выглядит примерно так:

static NSOperation *currentOperation = nil;
- (void) main
{
   // setting up autorelease pool, catching exceptions, etc
   @synchronized(lock) {
      if (currentOperation != nil) {
         [currentOperation cancel];
         [currentOperation waitUntilFinished];
      }
      currentOperation = self;
   }
   while (!calculationsFinished && ![self isCancelled]) {
      // do calculations
   }
   currentOperation = nil;
   // releasing autorelease pool, etc
}

Все это отлично работает, первая операция отменяется, а вторая ожидает ее завершения, а затем начинает вычисление.

Проблема в том, что между первой операцией, завершающей основной метод, и второй, выходящей из waitUntilFinished.

* 1013, уходит 3-10 секунд.что с этим делать?

Я также попытался вместо waitUntilFinished сделать вторую операцию зависимой от первой с помощью addDependency: (в методе init, а не в main).Это также работает, но имеет ту же проблему: начало второй операции составляет несколько секунд после окончания первого метода.

Ответы [ 2 ]

0 голосов
/ 07 января 2012

Я попытался воспроизвести проблему здесь, но мой код просто работает без такой задержки.Это мой код:

@interface PointsOperation : NSOperation {
@private
    bool calculationsFinished;
}

@property (nonatomic, assign) int tag;

@end


@implementation PointsOperation 

@synthesize tag;

static NSOperation *currentOperation = nil;
static NSString* lock = @"LOCK";

- (void) main
{
    NSLog(@"Before autoreleasepool with tag: %d", tag);
    @autoreleasepool {
        NSLog(@"Before lock");
        // setting up autorelease pool, catching exceptions, etc
        @synchronized(lock) {
            if (currentOperation != nil) {
                NSLog(@"Before cancel");
                [currentOperation cancel];
                NSLog(@"Before waitUntilFinished");
                NSDate* beforeWait = [NSDate date];
                [currentOperation waitUntilFinished];
                NSLog(@"After waitUntilFinished took %f seconds", [[NSDate date] timeIntervalSinceDate:beforeWait]);                
            }
            currentOperation = self;
        }
        NSLog(@"Before while loop");
        int i = 0;
        while (!calculationsFinished && ![self isCancelled]) {
            // do calculations
            [NSThread sleepForTimeInterval:1];
            NSLog(@"Inside while loop = %d", i);
            calculationsFinished = (++i > 10);
        }
        NSLog(@"After while loop: i = %d", i);
        currentOperation = nil;
        // releasing autorelease pool, etc
    }
    NSLog(@"%@", @"End of method");
}

@end

И вот как я его использую:

NSOperationQueue* q = [[NSOperationQueue alloc] init];
q.maxConcurrentOperationCount = 4;
for (int i = 0; i < 10; i++) {
    [q addOperation:[PointsOperation new]];
}

Результат, потраченный на waitUntilFinished, разделен на две категории:

After waitUntilFinished took 1.002624 seconds

и

After waitUntilFinished took 0.000749 seconds

, который, я думаю, зависит от времени звонка.

Возможно, вам следует предоставить больше кода, если это возможно, поскольку проблема может быть где-то еще в вашем коде.

0 голосов
/ 06 января 2012

Несмотря на свое название, метод cancel волшебным образом не отменяет операцию.

Отмена операции не заставляет ее немедленно прекратить то, что она делает.Хотя соблюдение значения, возвращаемого isCancelled, ожидается для всех операций, ваш код должен явно проверить значение, возвращаемое этим методом, и при необходимости прервать его.

http://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html

Если выне написал ваш код для проверки свойства isCancelled, поэтому поток операции будет выполняться до конца независимо от того, отменяете вы это или нет.

...