使用各种调度队列和NSOperationQueue来处理执行时间和性能 [英] Process execution time and performance using various dispatch queues and NSOperationQueue

查看:112
本文介绍了使用各种调度队列和NSOperationQueue来处理执行时间和性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


  1. 运行整个代码



    使用调度队列(GCD)创建自己的调度队列

  2. dispatch_queue_create



    使用高优先级全局队列



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



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

  3. c $ c> NSOperationQueue


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



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


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

      BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@ConfigurationofType:@xml] didFailWithError:& 
    if(success){
    DLog(@Parsing Complete);
    }
    else
    DLog(@解析错误%@,[错误描述]);


2.1使用 dispatch_queue_create - 执行时间 68 msec

  dispatch_queue_t backgroundQueue = dispatch_queue_create(BackQueue,NULL); 

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

dispatch_release(backgroundQueue);

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

  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:@ConfigurationofType:@ 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 msec



2.4与2.2类似2.2使用具有后台优先级的全局队列 DISPATCH_QUEUE_PRIORITY_BACKGROUND - 执行时间< 37 msec



2.5。使用 NSOperationQueue (子类化NSOperation) - 执行时间 - 36毫秒



帮助我找出这些执行时间,为什么他们这么奇怪(或我错过了一些东西)。为什么我得到最好的性能与方法1.
为什么DISPATCH_QUEUE_PRIORITY_BACKGROUND提供比HIGH更好的性能。
为什么NSOperationQueue给出比GCD更好的结果?

解决方案

更新:

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


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



  2. Queue 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


    所以我从中得出两个不太令人惊讶的结论:




    • 至少对于计算密集型背景操作,在各种并发背景技术之间似乎没有太多变化; p>


    • 当将任务分解为多个操作时,并发后台操作( NSOperationQueue ,GCD全局队列)性能优势。




    我不是建议,资源争用下的设备可能不会在调度方面表现出不同的行为(特别是GCD全局队列类型,请参阅 dispatch_queue_priority_t 会影响设备上排队的其他并发操作的操作调度。我只是试图证明经验证明,各种队列没有显着或多或少相互有效。说到这里,我个人不会使用 DISPATCH_QUEUE_PRIORITY_HIGH 在我的应用程序,因为我认为有可能影响核心的iOS功能。



    此外,为了充分公开,我应该承认,我关注的是材料性能差异。很可能一种机制或另一种机制可能提供以毫秒测量的性能差异。当我考虑不同的背景表现方法时,我更注重用户可观察的性能差异。






    原始答案:



    我调用了我的 parseManyTimes )from the main queue:

      [self parseManyTimes:@Main queue]; 

    Via 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:@personnelwithExtension:@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
    dispatch_queue_create:32.3


    I have a XML in my App bundle. I am parsing this XML file. I parsed this XML using NSXMLParser and using following ways:

    1. running the whole code serially on main thread
    2. Using dispatch queues (GCD):

      2.1 Creating my own dispatch queue using dispatch_queue_create

      2.2 using global queue with High Priority dispatch_get_global_queue

      2.3 using global queue with Low Priority

      2.4 using global queue with Background Priority

    3. using NSOperationQueue

    I checked the performance and total time taken in execution of parsing the XML file and found really weird (or may be correct) results.

    Following are the codes for above mentioned Parsing ways:

    1. Serial execution on main thread - Execution time 34 msec.

      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 Using dispatch_queue_create - Execution time 68 msec.

    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 using global queue with High Priority dispatch_get_global_queue - Execution time - 74 msec

    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 Similarly as 2.2 Using global queue with LOW Priority DISPATCH_QUEUE_PRIORITY_LOW - Execution time - 72 msec

    2.4 Similarly as 2.2 Using global queue with BACKGROUND Priority DISPATCH_QUEUE_PRIORITY_BACKGROUND - Execution time - 37 msec

    2.5. Using NSOperationQueue (subclassing the NSOperation) - Execution time - 36 msec

    Can anyone help me figure out these execution times and why are they so strange (or am I missing something). Why I am getting the best performance with method 1. Why is DISPATCH_QUEUE_PRIORITY_BACKGROUND giving better performance than HIGH. Why is NSOperationQueue giving better results than GCD?

    解决方案

    Update:

    I tested the various dispatch and operation queues for for two scenarios:

    1. Invoke a single job that repeatedly parse a large (725kb) XML file 100 times in a single operation; and

    2. Queue 100 operations to parse the same very large XML file one time each.

    My results (measured in seconds) on my iPhone 5 were as follows:

    1. For first scenario:

      Main queue: 18.7
      NSOperation: 18.4
      Global high-priority queue: 18.3
      Global default-priority queue: 18.4
      Global low-priority queue: 18.4
      Global background queue: 18.5
      Serial dispatch queue: 18.3
      

    2. For my second scenario:

      Main queue: 18.7
      NSOperation: 10.9
      Global high-priority queue: 10.9
      Global default-priority queue: 10.8
      Global low-priority queue: 10.8
      Global background queue: 11.0
      Serial dispatch queue: 18.5
      

    So I draw two fairly unsurprising conclusions from this:

    • For a computationally intensive background operation at the very least, there did not appear to be much variation between the various concurrent background techniques;

    • When breaking a task into multiple operations, the concurrent background operations (NSOperationQueue, GCD global queues) enjoyed a performance advantage over the serial operations.

    I'm not suggesting, though, that a device under resource contention might not exhibit different behavior in terms of scheduling (notably GCD global queue types, see dispatch_queue_priority_t, would affect the scheduling of operations with other concurrent operations queued on the device). I'm only trying to demonstrate empirically that the various queues are not significantly more or less efficient than each other. Having said that, I personally wouldn't use DISPATCH_QUEUE_PRIORITY_HIGH in my apps as I assume that would have the possibility of affecting core iOS functionality.

    Also, in the interest of full disclosure, I should admit that I'm focusing on material performance differences. It is quite possible that one mechanism or another might offer performance differences measured in msec. When I'm considering different approaches for background performance, I'm definitely more focused on user-observable performance differences.


    Original Answer:

    I invoked my parseManyTimes (which repeatedly parses a large XML file) from the main queue:

    [self parseManyTimes:@"Main queue"];
    

    Via NSOperation:

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

    Via global queues on GCD:

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

    and

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

    and

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

    and via a GCD serial queue:

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

    and the results did not differ significantly from each other (all between 32.2 and 32.5 seconds each). My parsing routine is:

    - (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];
    }
    

    I ran this on an iPad on a 725kb XML file. Clearly, the way I've structured this, with a very time consuming process, it will tend to was out any negligible variance in how the various queues are dispatched, but rather focus on the background operation. By it doesn't raise any concerns (for me at least) in material performance issues in the various techniques.

    The results were:

    Main queue: 32.3
    NSOperation: 32.2
    DISPATCH_QUEUE_PRIORITY_DEFAULT: 32.4
    DISPATCH_QUEUE_PRIORITY_HIGH: 32.3
    DISPATCH_QUEUE_PRIORITY_LOW: 32.5
    dispatch_queue_create: 32.3
    

    这篇关于使用各种调度队列和NSOperationQueue来处理执行时间和性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆