NSOperationQueue何时开始其第一次操作?

时间:2012-05-02 18:45:06

标签: cocoa-touch cocoa nsoperationqueue

我已经创建了一个测试项目,在我的主项目中使用它们之前,我正在测试我对NSOperationNSOperationQueue的假设。

我的代码非常简单,所以我将在这里包含所有内容。这是在启用ARC的情况下使用命令行基础项目。

Operation.h

#import <Foundation/Foundation.h>

@interface Operation : NSOperation

@property (readwrite, strong) NSString *label;

- (id)initWithLabel: (NSString *)label;

@end

Operation.m

#import "Operation.h"

@implementation Operation

- (void)main
{
    NSLog( @"Operation %@", _label);
}

- (id)initWithLabel: (NSString *)label
{
    if (( self = [super init] )) {
        _label = label;
    }
    return self;
}

@end

的main.m

#import <Foundation/Foundation.h>
#import "Operation.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {

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

        id create = [[Operation alloc] initWithLabel: @"create"];
        id update1 = [[Operation alloc] initWithLabel: @"update1"];
        id update2 = [[Operation alloc] initWithLabel: @"update2"];

        [update1 addDependency: create];
        [update2 addDependency: create];

        [queue addOperation: update1];
        [queue addOperation: create];
        [queue addOperation: update2];

        [queue waitUntilAllOperationsAreFinished];

    }
    return 0;
}

我的输出如下:

2012-05-02 11:37:08.573 QueueTest[1574:1b03] Operation create
2012-05-02 11:37:08.584 QueueTest[1574:1903] Operation update2
2012-05-02 11:37:08.586 QueueTest[1574:1b03] Operation update1

写完这篇文章并尝试了几个组合后,我发现当我重新排序这样的队列设置时:

    [queue addOperation: update1];
    [queue addOperation: create];
    [queue addOperation: update2];

    [update1 addDependency: create];
    [update2 addDependency: create];

    [queue waitUntilAllOperationsAreFinished];

我得到了相同的输出:

2012-05-02 11:38:23.965 QueueTest[1591:1b03] Operation create
2012-05-02 11:38:23.975 QueueTest[1591:1b03] Operation update1
2012-05-02 11:38:23.978 QueueTest[1591:1903] Operation update2

我应该注意到我在某些运行中发现update2在update1之前执行,但 行为并不令人惊讶。当我没有问过它时,为什么NSOperationQueue应该是确定性的呢?

做的令人惊讶的是,即使在添加依赖项之前所有内容都已添加到队列中,某些创建始终在update1和update2之前执行。

显然,这是一个愚蠢的事情,但它让我想知道:从我向队列添加操作到何时执行文档或以任何方式可预测之间的延迟?究竟什么时候NSOperationQueue开始处理添加的操作?

真的,最重要的是,NSOperationQueue等待的是什么,等待什么时候会等我咬我?不能防范?

2 个答案:

答案 0 :(得分:14)

  

显然,这是一个愚蠢的事情,但它让我想知道:从我向队列添加操作到何时执行文档或以任何方式可预测之间的延迟?究竟NSOperationQueue何时开始处理添加的操作?

后:

  • 您将操作添加到队列
  • 所有操作的依赖项已完成,
  • 队列没有更好的(在优先级方面)。

对于没有不满足的依赖关系的操作,这可能意味着立即。

  

进一步的实验似乎表明,NSOperationQueue会在当前线程通过[queue waitUntilAllOperationsAreFinished],[NSThread sleepForTimeInterval:0.000001]或中断的线程产生控制权时立即开始运行。

这个假设是假的,原因有两个:

  1. 抢先式多任务处理,在每个版本的OS X(以及iOS的每个版本)上完成,意味着调度程序可以随时中断您的线程。你不需要控制就失去控制。
  2. 当前OS X和iOS设备所拥有的多个核心意味着操作可以在addOperation:甚至返回之前开始(尽管这种极端不太可能 因为开销)。更重要的是,其他操作可以在第一个操作时运行。
  3. 这两点,尤其是后者,也意味着“秩序”的问题几乎减少到无意义。您在依赖关系树中排列的操作将按照该树的顺序启动,但否则根本没有顺序;你应该假设它们之间没有依赖关系的操作将同时运行,而不是一个又一个。

    启动操作后,向其添加依赖项无效。由于这可以在将其添加到队列后立即发生,因此如果您希望依赖项可靠地生效,那么必须之前添加依赖关系将操作添加到队列中

答案 1 :(得分:1)

进一步的实验似乎表明,NSOperationQueue会在当前线程通过[queue waitUntilAllOperationsAreFinished][NSThread sleepForTimeInterval: 0.000001]或中断的线程对其产生控制权时立即开始运行。

(如果有人有更好的答案,我很乐意听到,并会接受它。)