NSOperation waitUntilFinished等了很久

时间:2012-01-06 16:40:54

标签: ios multithreading nsoperation

我正在使用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结束的第二个操作之间需要3-10秒。

有没有人以前见过这个,知道怎么办?

我还尝试使用“addDependency:”(在init方法中,而不是main),而不是waitUntilFinished,使第二个操作依赖于第一个操作。这也有效,但也有同样的问题:第二个操作的开始是第一个方法完成后的几秒钟。

2 个答案:

答案 0 :(得分:0)

尽管名称如此,cancel方法并没有神奇地取消操作。

  

取消操作不会立即强制它停止它   是在做。虽然尊重isCancelled返回的值是   期望所有操作,您的代码必须明确检查值   通过此方法返回并根据需要中止。

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

如果你没有编写代码来检查isCancelled属性,那么无论你是否取消它,操作的线程都会运行到最后。

答案 1 :(得分:0)

我试图在这里重现这个问题,但我的代码工作正常,没有这样的延迟。这是我的代码:

@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

这取决于我认为的通话时间。

如果可能的话,也许你应该提供更多的代码,因为问题可能出现在代码的其他地方。