为了在 单一进程 中充分发挥多核的优势,我们有必要使用多线程技术,注意,多进程和GCD没有关系。在低层,GCD全局队列仅仅是工作线程池的抽象,队列中的block一旦可用,就会被调遣到工作线程中。除了主线程,提交至自定义队列的block最终也会通过全局队列进入相同的工作线程池。有两种途径可以充分利用多核心系统的性能:将单一任务或一组相关任务并发至全局队列中运算;将多个不相关任务或关联不紧密的任务并发至自定义队列中运算。
例如,遍历一个数组,并对每个元素操作:
for (id obj in array){
[self doSomethingLongTimeWith:obj];
}
假定doSomethingLongTimeWith:是线程安全的,则,使用GCD可以简单的实现平行运算:
for (id obj in array){
dispatch_async(DISPATCH_QUEUE_PRIORITY_DEFAULT, ^{
[self doSomethingLongTimeWith:obj];
});
}
如此,该段代码就可以在多核心上运行了。
但是,当我们对该数组元素操作完成后,还要对操作结果进行其它操作:
for (id obj in array){
[self doSomethingLongTimeWith:obj];
[self doSomethingWith:array];
}
这时候就不能dispatch_async了,同时,为了保证平行运算,也不能使用dispatch_sync。解决办法是使用dispatch_group。一个dispatch group可以将多个block组成一组,并监控这些block全部完成或等待全部完成时发出的消息。使用函数dispatch_group_create来创建,然后使用函数dispatch_group_async将block提交至一个dispatch queue,同时将它们添加到一个组。重新编写:
dispatch_group_t group = dispatch_group_create();
for (id obj in array){
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doSomethingLongTimeWith:obj];
});
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doSomethingWith:array];
});
}
这样,不仅数据元素都会被平行操作,后续操作有能异步执行,并且这些异步运算都会将程序的其他部分负载考虑在内。
对于同步执行,GCD提供了一个简化方法dispatch_apply。这个函数可以调用单一block多次,并平行运算,然后等待所有运算结束:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(array.count, queue, ^(size_t index) {
[self doSomethingIntensiveWith:array[index]];
});
[self doSomethingWith:array];
当然,如果异步执行的话,需要使用函数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[index]];
});
[self doSomethingWith:array];
});
虽然,GCD是轻量和低负载的,但是,将block提交至queue还是很耗资源的:block需要被拷贝和入队,同时,适当的工作线程需要被通知。将程序平行运算化是一种优化措施,在修改代码是一定要三思,确定修改是有益的。