iOS多线程之GCD
版权属于: LvesLi’s Blogging
原文地址: http://www.lvesli.com/?p=276
转载时必须以链接形式注明原始出处及本声明。
GCD是iOS中经常使用的多线程技术,是一个重点也是一个难点,今天来看看GCD怎么使用。
一、优势
1.Apple为多核并行计算提出的解决方案
2.自动管理线程的生命周期
二、同步和异步,串行队列和并行队列
学习GCD首先要了解同步和异步与串行和并行之间的关系
1.同步和异步区别就是是否创建新的线程,同步函数一定不会开辟新的线程,异步函数具有开辟多线程的能力,到底开不开还要看使用的是什么队列。
2.串行队列:一个任务执行完才能执行下一个任务;
并行队列:并行队列中的任务可以同时执行;
三、队列
Dispatch Queue是一个任务执行队列,可以让你异步或同步地执行多个Block或函数。Dispatch Queue是FIFO的,即先入队的任务总会先执行。目前有三种类型的Dispath Queue:
1.串行队列(Serial dispatch queue)
串行队列中一次只能处理一个任务(一个任务执行完毕后,再执行下一个任务),调用dispatch_queue_create创建;
dispatch_queue_t myQueue=dispatch_queue_create(“www.lvesli.com”, NULL);
2.并发队列(Concurrent dispatch queue)
并行队列中任务可以同时被执行(自动开启多个线程同时执行任务)。全局队列(Global Concurrent Dispatch Queues)。目前系统预定义了四个不同运行优先级的全局队列,我们可以通过dispatch_get_global_queue来获取它们。
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_get_global_queue第一个参数是队列的优先级,分别对应四个全局队列:
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND
3.主队列(Main dispatch queue)
主队列是一个特殊的串行队列,它是系统预定义的运行在主线程的一个Dispatch Queue。可以通过dispatch_get_main_queue来获取唯一的主队列。主队列中的任务一定是在主线程中执行的。
四、执行任务
同步函数,用同步的方式执行任务
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
异步函数,用异步的方式执行任务
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
下面举个栗子:
1>异步执行,图片下载
//1. 调用异步函数执行全局并行队列中的人物 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //执行下载图片的逻辑 NSLog(@"下载图片。。。 %@",[NSThread currentThread]); //2. 下载完毕,回到主线程更新UI dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"更新UI。。。 %@",[NSThread currentThread]); }); });
执行结果如下:
2015-07-20 22:29:44.205 GCD-0707[598:1093914] 下载图片。。。 {number = 2, name = (null)}
2015-07-20 22:29:44.256 GCD-0707[598:1092383] 更新UI。。。 {number = 1, name = main}
2>延时执行
//延时执行 NSLog(@"执行之前。。。 %@",[NSThread currentThread]); dispatch_time_t afterSecond= dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)); //两秒后异步执行 dispatch_after(afterSecond, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"我是两秒后执行的。。。 %@",[NSThread currentThread]); });
执行结果如下:
2015-07-20 22:45:43.856 GCD-0707[725:1364233] 执行之前。。。 {number = 1, name = main}
2015-07-20 22:45:45.947 GCD-0707[725:1364530] 我是两秒后执行的。。。 {number = 2, name = (null)}
3>一次性执行代码
// 一次性执行: static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"%@",@"只执行一次"); });
3>队列组
dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 执行1个耗时的异步操作 NSLog(@"执行1个耗时的异步操作。。。 %@",[NSThread currentThread]); }); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 执行1个耗时的异步操作 NSLog(@"执行1个耗时的异步操作。。。 %@",[NSThread currentThread]); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 等前面的异步操作都执行完毕后,回到主线程更新UI... NSLog(@"回到主线程 更新UI。。。 %@",[NSThread currentThread]); });
执行结果如下:
2015-07-20 22:57:50.221 GCD-0707[829:1569205] 执行1个耗时的异步操作。。。 {number = 3, name = (null)}
2015-07-20 22:57:50.221 GCD-0707[829:1565558] 执行1个耗时的异步操作。。。 {number = 2, name = (null)}
2015-07-20 22:57:50.222 GCD-0707[829:1565281] 回到主线程 更新UI。。。 {number = 1, name = main}
4>并行执行某段代码n次
//执行某个代码片段N次。 dispatch_apply(5, dispatch_get_global_queue(0, 0), ^(size_t index) { // 执行5次 NSLog(@"%@",[NSThread currentThread]); });
执行结果如下:
2015-07-20 23:18:55.104 GCD-0707[1083:1926255] {number = 1, name = main}
2015-07-20 23:18:55.104 GCD-0707[1083:1926527] {number = 2, name = (null)}
2015-07-20 23:18:55.104 GCD-0707[1083:1926523] {number = 4, name = (null)}
2015-07-20 23:18:55.104 GCD-0707[1083:1926524] {number = 3, name = (null)}
2015-07-20 23:18:55.105 GCD-0707[1083:1926255] {number = 1, name = main}
5>补充
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"111"); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"222"); NSLog(@"欢迎关注微信公众账号:lecoding"); }); NSLog(@"333"); }
执行结果: 只执行第一句输出,就卡死了,无法向下执行。在主线程中执行串行函数调用主队列中的任务就会造成相互等待状态,造成死循环。
2015-07-20 23:07:53.975 GCD-0707[985:1740328] 111