3

我的应用程序包中有一个 XML。我正在解析这个 XML 文件。NSXMLParser我使用和使用以下方式解析了这个 XML :

  1. 在主线程上串行运行整个代码
  2. 使用调度队列(GCD):

    2.1 使用dispatch_queue_create创建我自己的调度队列

    2.2 使用具有高优先级的全局队列dispatch_get_global_queue

    2.3 使用低优先级的全局队列

    2.4 使用具有后台优先级的全局队列

  3. 使用NSOperationQueue

我检查了执行解析 XML 文件的性能和总时间,发现结果非常奇怪(或者可能是正确的)。

以下是上述解析方式的代码:

  1. 主线程上的串行执行 - 执行时间34 毫秒。

    BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error];
    if (success) {
        DLog(@"Parsing Complete");
    }
    else
        DLog(@"Parse error %@",[error description]);
    

2.1 使用dispatch_queue_create - 执行时间68 毫秒

dispatch_queue_t backgroundQueue = dispatch_queue_create("BackQueue", NULL);

dispatch_async(backgroundQueue, ^{
    NSError *error = nil;
    BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error];
    if (success) {
        DLog(@"Parsing Complete");
    }
    else
        DLog(@"Parse error %@",[error description]);
});

dispatch_release(backgroundQueue);

2.2 使用具有高优先级dispatch_get_global_queue的全局队列- 执行时间 - 74 毫秒

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

dispatch_async(backgroundQueue, ^{
    NSError *error = nil;
    BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error];
    if (success) {
        DLog(@"Parsing Complete");
    }
    else
        DLog(@"Parse error %@",[error description]);
});

dispatch_release(backgroundQueue);

2.3 类似于 2.2 使用具有 LOW 优先级的全局队列DISPATCH_QUEUE_PRIORITY_LOW - 执行时间 - 72 毫秒

2.4 与 2.2 使用具有背景优先级的全局队列DISPATCH_QUEUE_PRIORITY_BACKGROUND - 执行时间 - 37 毫秒

2.5. 使用NSOperationQueue(继承 NSOperation) - 执行时间 - 36 毫秒

谁能帮我弄清楚这些执行时间以及为什么它们如此奇怪(或者我错过了什么)。为什么我使用方法 1 获得最佳性能。为什么 DISPATCH_QUEUE_PRIORITY_BACKGROUND 提供比 HIGH 更好的性能。为什么 NSOperationQueue 的结果比 GCD 好?

4

2 回答 2

6

更新:

我针对两种情况测试了各种调度和操作队列:

  1. 调用单个作业,在单个操作中重复解析大型 (725kb) XML 文件 100 次;和

  2. 排队 100 个操作,每次解析同一个非常大的 XML 文件。

我在 iPhone 5 上的结果(以秒为单位)如下:

  1. 对于第一种情况:

    主队列:18.7
    NSOperation:18.4
    全局高优先级队列:18.3
    全局默认优先级队列:18.4
    全局低优先级队列:18.4
    全局后台队列:18.5
    串行调度队列:18.3
    
  2. 对于我的第二种情况:

    主队列:18.7
    NSOperation:10.9
    全局高优先级队列:10.9
    全局默认优先级队列:10.8
    全局低优先级队列:10.8
    全局后台队列:11.0
    串行调度队列:18.5
    

因此,我从中得出两个相当不足为奇的结论:

  • 至少对于计算密集型后台操作而言,各种并发后台技术之间似乎没有太大差异。

  • 当将一个任务分解为多个操作时,并发后台操作(NSOperationQueueGCD 全局队列)比串行操作具有性能优势。

不过,我并不是说处于资源争用状态的设备在调度方面可能不会表现出不同的行为(特别是 GCD 全局队列类型,请参阅参考资料dispatch_queue_priority_t,这会影响设备上排队的其他并发操作的操作调度)。我只是想凭经验证明各种队列的效率并没有显着提高或降低。话虽如此,我个人不会DISPATCH_QUEUE_PRIORITY_HIGH在我的应用程序中使用,因为我认为这可能会影响核心 iOS 功能。

此外,为了充分披露,我应该承认我关注的是材料性能差异。一种或另一种机制很可能会提供以毫秒为单位的性能差异。当我考虑不同的后台性能方法时,我肯定更关注用户可观察到的性能差异。


原答案:

parseManyTimes我从主队列中调用了我的(它反复解析一个大的 XML 文件):

[self parseManyTimes:@"Main queue"];

通过NSOperation

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
     [self parseManyTimes:@"NSOperation"];
}];
queue = nil;

通过 GCD 上的全局队列:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_DEFAULT"];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_HIGH"];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_LOW"];
});

并通过 GCD 串行队列:

dispatch_queue_t dispatchQueue = dispatch_queue_create("org.rob.test", NULL);
dispatch_async(dispatchQueue, ^{
    [self parseManyTimes:@"dispatch_queue_create"];
});

并且结果彼此之间没有显着差异(均在 32.2 到 32.5 秒之间)。我的解析例程是:

- (void)parseManyTimes:(NSString *)type
{
    NSDate *startDate = [NSDate date];
    for (NSInteger i = 0; i < 100; i++)
        [self parse];

    NSLog(@"%@: %.1f", type, [[NSDate date] timeIntervalSinceDate:startDate]);
}

- (void)parse
{
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"personnel" withExtension:@"xml"];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    parser.delegate = self;
    [parser parse];
}

我在 iPad 上运行了一个 725kb XML 文件。显然,我构建这个的方式是一个非常耗时的过程,它倾向于消除各种队列的调度方式的任何可忽略不计的差异,而是专注于后台操作。通过它不会对各种技术的材料性能问题产生任何担忧(至少对我而言)。

结果是:

主队列:32.3
NSOperation: 32.2
DISPATCH_QUEUE_PRIORITY_DEFAULT:32.4
DISPATCH_QUEUE_PRIORITY_HIGH:32.3
DISPATCH_QUEUE_PRIORITY_LOW:32.5
调度队列创建:32.3
于 2012-12-18T07:59:30.693 回答
3

各种默认并发队列的性能只是相对的。“高”优先级仅意味着高于其他队列。我希望您的综合基准测试当时几乎没有发生其他事情,因此为什么所有队列似乎都表现相同。如果您想要实际演示权重,可以一次将一百个解析操作排入每个并发队列,并比较它们的执行时间。

另请注意,NSOperation 使用默认优先级并发队列来执行,因此正如您所看到的,性能基本相同。充其量你只是在测量 NSOperation 的开销,这是很小的。

在您的初步结果中,您看到了完全不同的时间安排。这些测量的条件是什么?例如,如果您在应用程序启动时执行此操作,那么将 XML 解析转移到另一个线程或队列可能会使其花费更长的时间,因为您的主线程和队列可能会与它竞争 CPU 时间。在这种情况下,更好的测试是整体启动时间,这将证明使用多个内核的好处。

于 2012-12-18T20:17:39.690 回答