Grand Central Dispatch vs NSThread

I created some test code for NSThread and 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); }); } 

And the results:

 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 works as I expected: tasks start simultaneously, and each thread sleeps for 1 second.

Package Manager does not work as I expected: why is the order consistent? Why does each cycle wait for the end of the previous cycle?

Thanks for the help.

+18
ios cocoa-touch grand-central-dispatch nsthread
Apr 13 '11 at 18:01
source share
3 answers

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.

+33
Apr 13 '11 at 18:20
source share

Try looking at this site: http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html

IOS says that dispatch_apply will depend on the queue passed, if the target queue is the parallel queue returned by dispatch_get_global_queue (this is your case), the block can be called at the same time.

So, I think it works, it just happens that it starts, as if it were running asynchronously. Also, which device on which the code is running can play a role in the result (as mentioned in @Caleb). But my suggestion, maybe try dispatch_async instead?

+7
Apr 14 2018-11-11T00:
source share

If someone wants to check which method works best for the spedify problem, here is the code:

 #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"); } 
+2
Apr 15 2018-11-11T00:
source share



All Articles