Grand Central Dispatch vs. NSThread

Car*_*rlJ 19 cocoa-touch nsthread grand-central-dispatch ios

我为NSThread和Grand Central Dispatch(GCD)创建了一些测试代码:

- (void)doIt:(NSNumber *)i
{
 sleep(1);
 NSLog(@"Thread#%i", [i intValue]);
}

- (IBAction)doWork:(id)sender
{

 for (int i = 0; 10 > i; i++) {
    NSNumber *t = [NSNumber numberWithInt:i];
    [NSThread detachNewThreadSelector:@selector(doIt:) toTarget:self withObject:t];
 }

 sleep(1);

 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 dispatch_apply(10, queue, ^(size_t i) {
    sleep(1);
    NSLog(@"GCD#%u",(int)i);
 });
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

2011-04-13 19:41:07.806 GDC[1494:5e03] Thread#0
2011-04-13 19:41:07.813 GDC[1494:6903] Thread#3
2011-04-13 19:41:07.812 GDC[1494:6403] Thread#2
2011-04-13 19:41:07.812 GDC[1494:5f03] Thread#1
2011-04-13 19:41:07.813 GDC[1494:6e03] Thread#4
2011-04-13 19:41:07.814 GDC[1494:7303] Thread#5
2011-04-13 19:41:07.814 GDC[1494:7803] Thread#6
2011-04-13 19:41:07.815 GDC[1494:7d03] Thread#7
2011-04-13 19:41:07.815 GDC[1494:8203] Thread#8
2011-04-13 19:41:07.816 GDC[1494:8703] Thread#9
2011-04-13 19:41:08.812 GDC[1494:707] GCD#0
2011-04-13 19:41:09.816 GDC[1494:707] GCD#1
2011-04-13 19:41:10.819 GDC[1494:707] GCD#2
2011-04-13 19:41:11.825 GDC[1494:707] GCD#3
2011-04-13 19:41:12.828 GDC[1494:707] GCD#4
2011-04-13 19:41:13.833 GDC[1494:707] GCD#5
2011-04-13 19:41:14.838 GDC[1494:707] GCD#6
2011-04-13 19:41:15.848 GDC[1494:707] GCD#7
2011-04-13 19:41:16.853 GDC[1494:707] GCD#8
2011-04-13 19:41:17.857 GDC[1494:707] GCD#9
Run Code Online (Sandbox Code Playgroud)

NSThreads按预期工作:任务同时运行,每个线程休眠1秒.

dispatch_apply不能像我预期的那样工作:为什么订单顺序?为什么每个循环都等到上一个循环结束?

谢谢您的帮助.

Cal*_*leb 34

因为您的设备只有一个处理器,GCD可能只创建一个用于执行块的线程,并且您的块按顺序执行.但是,您创建了10个不同的线程,每个线程都可以获得一小部分可用的处理时间.幸运的是,睡眠不是处理器密集型的,因此所有线程都可以很好地协同运行.在具有4或8个处理核心的机器上尝试类似的测试,您会看到GCD并行运行更多的块.

关于GCD的好处并不是它必然提供比线程更好的性能,而是程序员不必考虑创建线程或将线程数与可用处理器的数量相匹配.您可以创建许多小任务,这些任务将在处理器可用时执行,并让系统为您安排这些任务.

编辑:我在Mac上的一个简单的命令行程序中使用了你的代码.正如我在下面的评论中所提到的,并且在@ Ren-D的答案中也提到过,使用dispatch_async()而不是dispatch_apply()产生很大的不同.这是我使用的代码:

- (void)doIt:(NSNumber *)i
{
    for (int j = 0; j < MAX_COUNT; j++)
        ;
    NSLog(@"Thread#%i", [i intValue]);
}

- (void)doWork:(id)sender
{
    for (int i = 0; i<10; i++) {
        NSNumber *t = [NSNumber numberWithInt:i];
        [NSThread detachNewThreadSelector:@selector(doIt:) toTarget:self withObject:t];
    }

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    for (size_t i = 0; i<10; i++) {
         dispatch_async(queue, ^(void) {
            for (int j = 0; j < MAX_COUNT; j++)
                ;
            NSLog(@"GCD#%u",(int)i);
        });
    }
    NSLog(@"Done.");
    sleep(15);
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我用一些花费一些时间计算的循环替换了您的sleep()调用for.(我在MacBook Pro上运行代码 - MAX_COUNT如果你在iPhone上运行,你可能想要调整向下的值.)如果sleep()在线程和块中使用,那么dispatch_async()使块的行为就像线程一样 - 所有块几乎同时运行并完成.切换到计数会改变该行为 - 多个线程全部并发运行,但这些块在组中执行(我的机器有两个处理器核心,因此它以两个为一组运行块).这正如你所期望的那样; GCD的工作是尽可能快地排队任务并完成它们,充分利用可用资源,而不是尽可能多地同时运行任务.

这是上面代码的输出:

2011-04-14 02:48:46.840 BlockTest[14969:903] Hello, World!
2011-04-14 02:48:47.104 BlockTest[14969:903] Done.
2011-04-14 02:48:52.834 BlockTest[14969:1503] Thread#0
2011-04-14 02:48:52.941 BlockTest[14969:4f03] GCD#0
2011-04-14 02:48:52.952 BlockTest[14969:5003] GCD#1
2011-04-14 02:48:52.956 BlockTest[14969:4703] Thread#8
2011-04-14 02:48:53.030 BlockTest[14969:3703] Thread#4
2011-04-14 02:48:53.074 BlockTest[14969:2b03] Thread#1
2011-04-14 02:48:53.056 BlockTest[14969:4b03] Thread#9
2011-04-14 02:48:53.065 BlockTest[14969:3b03] Thread#5
2011-04-14 02:48:53.114 BlockTest[14969:3303] Thread#3
2011-04-14 02:48:53.138 BlockTest[14969:4303] Thread#7
2011-04-14 02:48:53.147 BlockTest[14969:3f03] Thread#6
2011-04-14 02:48:53.156 BlockTest[14969:2f03] Thread#2
2011-04-14 02:48:53.909 BlockTest[14969:4f03] GCD#2
2011-04-14 02:48:53.915 BlockTest[14969:5003] GCD#3
2011-04-14 02:48:54.700 BlockTest[14969:4f03] GCD#4
2011-04-14 02:48:54.721 BlockTest[14969:5003] GCD#5
2011-04-14 02:48:55.508 BlockTest[14969:4f03] GCD#6
2011-04-14 02:48:55.550 BlockTest[14969:5003] GCD#7
2011-04-14 02:48:56.321 BlockTest[14969:4f03] GCD#8
2011-04-14 02:48:56.345 BlockTest[14969:5003] GCD#9
Run Code Online (Sandbox Code Playgroud)

请注意,除了其中一个线程之外,其中两个块实际上已完成.另外:sleep(15)代码末尾只是让程序终止之前让线程和块记录它们的消息.根据您将代码粘贴到哪种程序,您可能不需要它.

  • +1精彩的答案,实际的实验室工作来备份预感.哇. (6认同)
  • 一点也不.请尝试使用dispatch_async(). (5认同)

Rpr*_*ata 7

试着看看这个网站:http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html

在IOS环境中,据说dispatch_apply将依赖于传入的队列,如果目标队列是返回的并发队列dispatch_get_global_queue(这是你的情况),则可以同时调用该块.

所以,我认为它正在工作,只是碰巧它运行就好像它以异步方式运行.此外,运行代码的设备可能会对结果起作用(如@Caleb所述).但我的建议是,也许试试dispatch_async呢?