简体   繁体   English

NSOperation waitUntilFinished等待很长时间

[英]NSOperation waitUntilFinished waits a long time

I am using an NSOperation subclass (called PointsOperation) to do some calculations in the background in my app. 我正在使用NSOperation子类(称为PointsOperation)在后台在我的应用程序中进行一些计算。 Due to user behaviour, these calculations might need to be canceled, and new calculations started. 由于用户的行为,可能需要取消这些计算,并开始新的计算。 In that case, I will create a new PointsOperation instance, and add it to the same NSOperationQueue as the first one. 在这种情况下,我将创建一个新的PointsOperation实例,并将其添加到与第一个实例相同的NSOperationQueue中。 As the first thing in the main method of the PointsOperation, it will check whether another operation is already running, and cancel it. 作为PointsOperation的main方法的第一件事,它将检查是否已在运行另一个操作,并将其取消。

Because the operations are using some shared caches, they cannot be (and don't need to be) running in parallel. 由于这些操作使用的是某些共享缓存,因此它们不能(也不需要)并行运行。 Therefore, the second operation will wait until the first one has finished. 因此,第二个操作将一直等到第一个操作完成。 The resulting code for the main method looks something like this: 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
}

This all works fine, the first operation gets cancelled, and the second waits for it to finish, and then starts calculating. 一切正常,第一个操作被取消,第二个等待它完成,然后开始计算。

The problem is: it takes 3-10 seconds between the first operation ending the main method, and the second one to come out of the waitUntilFinished . 问题是:从第一个操作结束main方法到第二个操作从waitUntilFinished退出,这需要3到10秒的waitUntilFinished

Does anybody have seen this before and knows what to do about that? 有人以前见过这个,并且知道该怎么做吗?

I have also tried, instead of the waitUntilFinished , to make the second operation dependent on the first, with "addDependency:" (in the init method, rather than the main). 我还试图,代替waitUntilFinished ,使第二操作依赖于所述第一,用“addDependency:”(在init方法中,而不是主)。 That also works, but has the same problem: the start of the second operation is a number of seconds behind the finish of the first method. 这也可行,但存在相同的问题:第二个操作的开始比第一个方法的完成晚了几秒钟。

Despite of its name, the cancel method does not magically cancel the operation. 尽管有其名称, cancel方法并不能神奇地取消该操作。

Canceling an operation does not immediately force it to stop what it is doing. 取消操作不会立即强制其停止正在执行的操作。 Although respecting the value returned by the isCancelled is expected of all operations, your code must explicitly check the value returned by this method and abort as needed. 尽管尊重所有操作均应遵循isCancelled返回的值,但是您的代码必须显式检查此方法返回的值并根据需要中止。

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

If you did not write your code to check isCancelled property, so the operation's thread will run to the end no matter you cancel it or not. 如果您没有编写代码来检查isCancelled属性,那么无论您是否取消操作,该操作的线程都会运行到最后。

I tried to reproduce the issue here but my code just work fine with no such delay. 我试图在此处重现该问题,但我的代码运行正常,没有出现此类延迟。 This is my code: 这是我的代码:

@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

And here's how I use it: 这是我的用法:

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

The result of time took by waitUntilFinished came in two categories: waitUntilFinished花费的时间分为两类:

After waitUntilFinished took 1.002624 seconds

and

After waitUntilFinished took 0.000749 seconds

which depends on the timing of the call I think. 这取决于我认为的通话时间。

Maybe you should provide more of your code if possible, as problem might be somewhere else in your code. 可能的话,也许您应该提供更多的代码,因为问题可能出在代码的其他地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM