【问题标题】:When does an NSOperationQueue start its first operation?NSOperationQueue 什么时候开始它的第一个操作?
【发布时间】:2012-05-12 06:50:34
【问题描述】:

我创建了一个测试项目,我在其中测试我对NSOperationNSOperationQueue 的假设,然后在我的主项目中使用它们。

我的代码非常简单,所以我将在此处包含所有代码。这是使用启用了 ARC 的命令行 Foundation 项目。

操作.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 不是我要求的确定性?

感到惊讶的是,即使在添加依赖项之前将所有内容都添加到队列中,无论如何 create 总是在 update1 和 update2 之前执行。

显然,这是一件愚蠢的事情,但它让我想知道:我将操作添加到队列和执行它之间的延迟是否记录在案,或者以任何方式可预测? NSOperationQueue 究竟什么时候开始处理添加的操作?

真的,最重要的是,NSOperationQueue 究竟在等待什么?等待何时会以某种我无法防御的方式咬我?

【问题讨论】:

  • 我怀疑这在任何方面都是可预测或可靠的。这是一个经典的比赛条件。我想设置依赖关系的当前线程可能具有优势,因为它已经在运行,但不依赖于此。如果有任何机会让另一个线程开始做某事所花费的时间会“咬”你,那么你做错了。
  • 谢谢肯。 :) 是的,我打算比我的测试代码更小心。但我的一部分天性是当我发现一些不应该工作的东西时,除了确定它应该工作我想了解它。 NSOperationQueue 从不同的线程运行并且(通常)不具有该边缘在这里最有意义。我想这会导致人们无法找到的错误。

标签: cocoa-touch cocoa nsoperationqueue


【解决方案1】:

显然,这是一件愚蠢的事情,但它让我想知道:我将操作添加到队列和执行它之间的延迟是否记录在案,或者以任何方式可预测? NSOperationQueue 究竟什么时候开始处理添加的操作?

之后:

  • 您将操作添加到队列中,并且
  • 所有操作的依赖都已完成,并且
  • 队列没有比这更好的事情了(就优先级而言)。

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

进一步的实验似乎表明,一旦当前线程通过 [queue waitUntilAllOperationsAreFinished]、[NSThread sleepForTimeInterval: 0.000001] 或中断的线程将控制权交给它,NSOperationQueue 就会立即开始运行操作。

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

  1. 在每个 OS X 版本(以及每个 iOS 版本)上执行的抢先式多任务处理意味着调度程序可以随时中断您的线程。您无需放弃控制即可失去控制。
  2. 每个当前的 OS X 和 iOS 设备都具有多个内核,这意味着操作可以addOperation: 甚至返回之前开始(尽管这种极端不太可能简单 因为开销)。更重要的是,其他操作可能能够在第一个操作的同时运行。

这两点,尤其是后者,也意味着“秩序”问题几乎变成了无稽之谈。您在依赖树中安排的操作将按该树的顺序开始,否则根本没有顺序;您应该假设它们之间没有依赖关系的操作将同时运行,而不是一个接一个地运行。

一旦启动操作,添加依赖项将不起作用。由于这可能会在将其添加到队列后立即发生,因此如果您希望依赖项可靠地生效,则必须在将操作添加到队列之前将依赖项添加到操作中 .

【讨论】:

    【解决方案2】:

    进一步的实验似乎表明,一旦当前线程通过[queue waitUntilAllOperationsAreFinished][NSThread sleepForTimeInterval: 0.000001] 或中断线程将控制权交给它,NSOperationQueue 就会立即开始运行操作。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-01
      • 2018-07-04
      • 2021-11-04
      • 2011-10-14
      • 2011-05-16
      相关资源
      最近更新 更多