大中央调度与NSThread

我为NSThread和Grand Central Dispatch(GCD)创build了一些testing代码:

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

结果是:

 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 

NSThreads按我的预期工作:任务同时运行,每个线程hibernate1秒钟。

dispatch_apply不能按我的预期工作:为什么顺序是顺序的? 为什么每个循环都要等到前一个循环结束?

谢谢您的帮助。

由于您的设备只有一个处理器,因此GCD可能只会创build一个用于执行块的线程,并且您的块将按顺序执行。 但是,您已经创build了10个不同的线程,而且每个线程都获得了一小部分可用的处理时间。 幸运的是,睡眠并不是处理器密集型的,所以你所有的线程都运行得非常好。 在有4个或8个处理核心的机器上试一下类似的testing,你会看到GCD并行运行更多的块。

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

编辑:我在你的代码中玩了一下我的Mac上的一个简单的命令行程序。 正如我在下面的评论中所build议的,在@ 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); } 

正如你所看到的,我用花费了一些时间计算的循环replace了sleep()调用。 (我在MacBook Pro上运行代码 – 如果您在iPhone上运行,您可能需要向下调整MAX_COUNT的值)。如果在线程和块中都使用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 

请注意,其中两个块实际上完成之前,但其中一个线程。 另外:代码结尾处的sleep(15)就是让程序终止之前,线程和程序块logging它们的消息。 根据您将代码粘贴到哪种程序,您可能不需要它。

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

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

所以,我认为它正在工作,就好像它运行asynchronous一样。 另外,运行代码的设备可以对结果起作用(就像@Caleb所提到的那样)。 但我的build议是,也许尝试dispatch_async

如果有人想testing,哪个方法是最好的spedify问题,这里是代码:

 #define MAX_COUNT 99999999 #define HOW_MUCH 10 - (void)doIt:(NSNumber *)i { for (int j = 0; j < MAX_COUNT; j++) ; NSLog(@"Thread#%i", [i intValue]); } - (IBAction)doWork:(id)sender { NSLog(@"START"); for (int i = 0; i < HOW_MUCH; i++) { NSNumber *t = [NSNumber numberWithInt:i]; [NSThread detachNewThreadSelector:@selector(doIt:) toTarget:self withObject:t]; } sleep(3); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(HOW_MUCH, queue, ^(size_t i) { for (int j = 0; j < MAX_COUNT; j++) ; NSLog(@"GCD APPLY %u",(int)i); }); sleep(3); for (size_t k = 0; k < HOW_MUCH; k++) { dispatch_async(queue, ^(void) { for (int j = 0; j < MAX_COUNT; j++) ; NSLog(@"GCD ASYNC#%u",(int)k); }); } sleep(10); NSLog(@"DONE"); }