Since your device has only one processor, a GCD probably only creates one thread to execute blocks, and your blocks execute sequentially. However, you created 10 different threads, and each one receives a small fraction of the available processing time. Fortunately, hibernation is not very processor saturated, so all of your threads work together successfully. Try a similar test on a machine with 4 or 8 processor cores, and you will see that GCD runs more of your blocks in parallel.
The good thing about GCD is not that it necessarily provides better performance than threads, it is that the programmer does not need to think about creating threads or comparing the number of threads with the number of available processors. You can create many small tasks that will be performed as the processor becomes available and allows the system to schedule these tasks for you.
Edit: I played around with your code a bit on a simple command line on my Mac. As I suggested in my comment below, and also mentioned @ Ren-D's answer using dispatch_async () rather than dispatch_apply () is of great importance. Here is the code I used:
- (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); }
As you can see, I replaced your sleep () calls with for loops that do the time counting. (I ran the code on a MacBook Pro - you can set the MAX_COUNT value down if you work on the iPhone.) If you use sleep () both in streams and in a block, then dispatch_async () makes the blocks behave exactly the same as threads - all blocks work simultaneously and completely at about the same time. Switching to countable changes, the behavior of which is the simultaneous execution of several threads, but the blocks are executed in groups (my machine has two processor cores, so it managed blocks in groups of two). This is exactly as you expected; The task of GCD is to queue tasks and complete them as quickly as possible, using the maximum available resources, and not launch as many tasks as possible.
The code above is displayed here:
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
Note that two of the blocks are actually finished in front of all but one of the threads. Also: sleep (15) at the end of the code is there so that threads and blocks register their messages before the program ends. Depending on what program you are inserting into the code, you might not need it.