GCD系列 之(二): 多核心的性能
全局队列的并发执行
for(id obj in array) [self doSomethingIntensiveWith:obj];
假设,每个元素要做的事情-doSomethingIntensiveWith:
是线程安全的且可以同时并发执行多个。一个array通常包含多个元素,这样的话,我们可以很简单地使用GCD来平行运算:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); for(id obj in array) dispatch_async(queue, ^{ [self doSomethingIntensiveWith:obj]; });
这样充分利用了多核系统的性能。
有时候,我们需要在完成对数组的每一个数据操作之后,再对数组整体进行操作,那么就有一个问题,什么时候,这些数组的数据的并发执行任务都完成了?
dispatch group
解决这个问题的一种方法是使用dispatch group。一个dispatch group可以用来将多个block组成一组以监测这些Block全部完成或者等待全部完成时发出的消息。使用函数dispatch_group_create来创建,然后使用函数dispatch_group_async来将block提交至一个dispatch queue,同时将它们添加至一个组。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); for(id obj in array) dispatch_group_async(group, queue, ^{ [self doSomethingIntensiveWith:obj]; }); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); dispatch_release(group); [self doSomethingWith:array];
如果后续的对数组的整体处理也是可以异步的,那么可以这样:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); for(id obj in array) dispatch_group_async(group, queue, ^{ [self doSomethingIntensiveWith:obj]; }); dispatch_group_notify(group, queue, ^{ [self doSomethingWith:array]; }); dispatch_release(group);
如果对数组的处理-doSomethingWith:需要在主线程中执行,比如操作GUI,那么我们只要将main queue而非全局队列传给dispatch_group_notify函数就行了。
dispatch_apply
同步执行,GCD提供了一个简化方法叫做dispatch_apply。该函数按指定的次数将指定的Block追加到指定的Dispatch Queue中,指定的次数的Block将会被异步执行,dispatch_apply函数会等待全部处理执行结束,接着进行后面的代码序列。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply([array count], queue, ^(size_t index){ [self doSomethingIntensiveWith:[array objectAtIndex:index]]; }); [self doSomethingWith:array];
dispatch_apply函数是没有异步版本的,实现异步要用dispatch_async函数将所有代码推到后台实现异步。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ dispatch_apply([array count], queue, ^(size_t index){ [self doSomethingIntensiveWith:[array objectAtIndex:index]]; }); [self doSomethingWith:array]; });
dispatch_queue_t queue = dispatch_get_global_queu(0, 0); dispatch_apply(10, queue, ^(size_t index){ NSLog(@"%zu", index); }); NSLog(@"done");
执行结果:
4 3 5 0 2 1 7 6 9 8 done
- 第一个参数为重复次数
- 第二个参数为追加对象的Dispatch Queue
- 第三个参数为追加的处理。
由于dispatch_apply函数与dispatch_sync函数相同,会等待处理执行结束,因此推荐在dispatch_async函数中非同步地执行dispatch_apply函数
NSArray *array = @[@"1", @"2", @"3", @"4", @"5", @"6"]; dispatch_queue_t queue = dispatch_get_global_queue(0, 0); dispatch_async(queue, ^{ dispatch_apply([array count], queue, ^(size_t index) { NSLog(@"%zu : %@", index, [array objectAtIndex:index]); }); dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"currentThread = %@", [NSThread currentThread]); NSLog(@"done"); }); });