在此小编做一个自我学习的总结和对iOS开发新新人的小小福利吧。
直奔主题的吧,讲讲GCD:Grand Central Dispatch(多线程优化技术),是Apple提供的一套更底层,更高效的并发编程技术,属于纯C语言编写,基于Block实现的,支持同步或者异步任务处理,串行或并行的处理队列,非系统调用的信号量机制,定时任务处理、进程、文件或者网络监听任务等。特别的:GCD可以自动的根据系统负载来增减线程数量,同时也无需加锁或其他同步机制。
GCD的常用属性及方法:
Dispatch Queue(执行处理的等待队列),它包含Serial Dispatch Queue(串行队列)和 Concurrent Dispatch Queue(并发队列)
Serial Dispatch Queue:(串行队列)等待当前正在执行的任务结束再处理下一个任务,一个线程同时执行一个任务,避免数据的竞争,可以生成多个Serial Dispatch Queue 并行执行。
Concurrent Dispatch Queue:(并发队列)不等待当前正在执行的任务结束便处理下一个任务,多个线程同时执行多个任务,具体有多少线程根据CPU核数和其负载来决定。
Main Dispatch Queue:(主队列),在主线程中执行的队列,因为主线程只有一个,因此Main Dispatch Queue就是Serial Dispatch Queue。一切跟UI有关的操作必须放在主队列中。
Global Dispatch Queue:(全局队列),它是所有应用程序都能使用的Concurrent Dispatch Queue。他也是并发队列的一种,可看做系统创建的并发队列。
同步:sync,任务串行执行。
异步:async,任务并行执行。
注意:
添加同步任务,无论是串行还是并行都不会开启多线程,都在当前线程中执行,运行完毕后才会执行下面的代码。
添加异步任务到串行队列有可能会开启多线程。
添加异步任务到全局队列会开启多线程,所添加的任务并发执行。
实例:添加同步任务到串行队列
//同步添加到串行队列 - (void)addTaskSerialQueueForSync { //创建一个串行队列 dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL); //添加同步任务1 //将任务1 同步添加到串行队列中去 dispatch_sync(serialQueue, ^{ for (int i = 0; i < 10; i++) { NSLog(@"任务1:%i", i); } }); NSLog(@"任务1执行完毕"); //添加同步任务2 //将任务2 同步添加到串行队列中去 dispatch_sync(serialQueue, ^{ for (int i = 0; i < 10; i++) { NSLog(@"任务2:%i", i); } }); NSLog(@"任务2执行完毕"); /* 执行结果:先添加任务1,执行完毕后添加任务2并执行完毕 */ }
//同步添加到并发队列 - (void)addTaskConcurrentQueueForSync { //创建并发队列 //普通的并发队列 // dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT); //全局队列 dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //添加同步任务3 //将任务3 同步添加到串行队列中去 dispatch_sync(globalQueue, ^{ for (int i = 0; i < 10; i++) { NSLog(@"任务3:%i", i); } }); NSLog(@"任务3执行完毕"); //添加同步任务4 //将任务4 同步添加到串行队列中去 dispatch_sync(globalQueue, ^{ for (int i = 0; i < 10; i++) { NSLog(@"任务4:%i", i); } }); NSLog(@"任务4执行完毕"); /* 执行结果:先添加任务3,执行完毕后添加任务4并执行完毕 */ }
//异步添加到串行队列 - (void)addTaskSerialQueueForAsync { //创建串行队列 dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //将任务5 异步添加到串行队列中去 dispatch_async(queue, ^{ for (int i = 0; i < 10; i++) { NSLog(@"任务5:%i", i); } }); NSLog(@"任务5添加完毕"); //将任务6 异步添加到串行队列中去 dispatch_async(queue, ^{ for (int i = 0; i < 10; i++) { NSLog(@"任务6:%i", i); } }); NSLog(@"任务6添加完毕"); /* 执行结果:先添加完成任务5,马上开始执行任务5,还未执行完毕时有添加完成了任务6,当任务5执行完之后才会执行任务6(因为是串行队列) */ }
//异步添加到并发队列 - (void)addTaskConcurrentQueueForAsync { //全局队列 dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //将任务7 异步添加到串行队列中去 dispatch_async(globalQueue, ^{ for (int i = 0; i < 10; i++) { NSLog(@"任务7:%i", i); } }); NSLog(@"任务7添加完毕"); //将任务8 异步添加到串行队列中去 dispatch_async(globalQueue, ^{ for (int i = 0; i < 10; i++) { NSLog(@"任务8:%i", i); } }); NSLog(@"任务8添加完毕"); /* 执行结果:先添加任务7,立刻开始执行任务7,随后立刻添加完成任务8(此时任务7并没有执行完),这时任务7与任务8同时执行。 */ }
1. 创建队列dispatch_queue_create() / 获取全局队列,主队列
2. 同步添加任务: 需要等待任务s的执行,才能继续运行
3. 异步添加任务: 无需等待任务的执行,能过直接运行下面的代码
GCD的一些其他方法
延迟任务:dispatch _after:等待指定的时间后,异步添加到一个block块到指定的队列里面,不堵塞当前的线程。
- (void)delay { //创建调用时机 //参数1:参照时间,基础时间 //参数2:延迟时间,以纳秒为单位的整数 dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5); /** * 延迟调用 * * @param when 调用的时间 * @param queue 所在的队列 * @param void 调用的任务 * */ dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@"延迟5秒后调用的任务"); }); NSLog(@"延迟任务 添加完毕"); /* 执行结果:先添加延迟任务完毕,经过5秒后执行完打印“延迟5秒后调用的任务” */ //其他延时调用的方法 // [self performSelector:<#(nonnull SEL)#> withObject:<#(nullable id)#> afterDelay:<#(NSTimeInterval)#>]; // [NSObject cancelPreviousPerformRequestsWithTarget:<#(nonnull id)#>]; }
queue 的 suspend reference count + 1。
恢复任务:dispatch_resume:恢复队列中被挂起的任务,使这些任务能够继续执行
queue 的 suspend reference count - 1 。注意:必须平衡使用suspend和resume。
组任务:
dispatch_group_async:监视一组block任务的完成,多个任务都结束后的一个汇总处理。
dispatch_group_notify:所有任务执行完成后汇总,不阻塞当前线程。
dispatch_group_wait:等待直到所有任务执行结束,中途不能取消,阻塞当前线程。
- (void)groupTask { //创建队列 dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //创建一个任务组 dispatch_group_t group = dispatch_group_create(); //向任务组中 添加任务 dispatch_group_async(group, global, ^{ NSLog(@"任务1 开始"); [NSThread sleepForTimeInterval: 2]; NSLog(@"任务1 结束"); }); dispatch_group_async(group, global, ^{ NSLog(@"任务2 开始"); [NSThread sleepForTimeInterval:3]; NSLog(@"任务2 结束"); }); dispatch_group_async(group, global, ^{ NSLog(@"任务3 开始"); [NSThread sleepForTimeInterval:15]; NSLog(@"任务3 结束"); }); //任务汇总回调 dispatch_group_notify(group, global, ^{ NSLog(@"所有任务 已完成!"); }); //在任务开始5秒后,来查看任务的执行情况 dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC); //等待直到某一时刻,然后去查看任务组中任务的完成情况 //等待操作,会阻塞线程 long result = dispatch_group_wait(group, time); //当time = DISPATCH_TIME_FOREVER 时代表永久等待,直到任务完成 // long result = dispatch_group_wait(group, DISPATCH_TIME_FOREVER); if (result == 0) { NSLog(@"所有任务执行成功"); } else { NSLog(@"某些任务没有执行完毕"); } /* 执行结果:任务123依次添加到任务组中去执行,因为任务3休眠时间较长,而等待操作只有5秒,因此会检测到有任务没有执行完毕,等15秒过后,notif执行所有任务已经执行完成的通知。 */ }