在说GCD之前,先说几个核心的概念
任务:执行什么操作
队列:用来存放任务
1 - 并发队列(Concurrent Dispatch Queue) 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务) 并发功能只有在异步(dispatch_async)函数下才有效
2 - 串行队列(Serial Dispatch Queue)
让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务) |
同步和异步的区别
同步:只能在当前线程中执行任务,不具备开启新线程的能力
异步:可以在新的线程中执行任务,具备开启新线程的能力 |
GCD使用步骤
一、创建任务
二、将任务添加到队列中
GCD会自动将队列中的任务取出,放到对应的线程中执行
任务的取出遵循队列的FIFO原则:先进先出,后进后出
GCD线程队列的创建方法
1、创建一个串行队列
/** * 创建一个串行队列 * * @param "Mazy" 队列的标示符 * @param DISPATCH_QUEUE_SERIAL 串行队列 DISPATCH_QUEUE_CONCURRENT 并发队列 * * @return 返回串行队列 */ dispatch_queue_t serialQueue = dispatch_queue_create("Mazy", DISPATCH_QUEUE_SERIAL); |
2、创建一个并发队列
/** * 创建一个并发队列 * * @param "Mazy" 队列的标示符 * @param DISPATCH_QUEUE_CONCURRENT 并发队列 * * @return 返回并发队列 */ dispatch_queue_t concurrentQueue = dispatch_queue_create("Mazy", DISPATCH_QUEUE_CONCURRENT); |
3、获得全局并发队列
/** * 获得全局并发队列 * * @param DISPATCH_QUEUE_PRIORITY_DEFAULT 线程队列的优先级
DISPATCH_QUEUE_PRIORITY_HIGH 2 高
DISPATCH_QUEUE_PRIORITY_DEFAULT 0 一般 默认
DISPATCH_QUEUE_PRIORITY_LOW (-2) 低
DISPATCH_QUEUE_PRIORITY_BACKGROUND 很低
* @param 0 系统保留参数
*
* @return 返回全局并发队列
*/
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0); |
3、获得主队列
/** * 获得主队列 * * @return 返回主线程队列 */ dispatch_queue_t mainQueue = dispatch_get_main_queue(); |
同步/异步 + 串行/并发队列的组合
1、同步 + 串行队列
// 同步 + 串行队列:不会开启新的线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务 -(void)sync_serial { // 创建一个串行队列 dispatch_queue_t queue = dispatch_queue_create("Mazy", DISPATCH_QUEUE_SERIAL); // 同步执行三个任务 dispatch_sync(queue, ^{ NSLog(@"1 %@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2 %@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3 %@",[NSThread currentThread]); }); } |
打印结果:
总结:没有创建新线程,主线程执行任务,任务串行执行
2、异步 + 串行队列
// 异步 + 串行队列:开启新的线程,但只开启一条 -(void)async_serial { // 创建一个串行队列 dispatch_queue_t queue = dispatch_queue_create("Mazy", DISPATCH_QUEUE_SERIAL); // 异步执行三个任务 dispatch_async(queue, ^{ NSLog(@"1 %@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2 %@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3 %@",[NSThread currentThread]); }); } |
打印结果:
总结:开启了一条线程,任务串行执行
3、同步 + 并发队列
// 同步 + 并发队列:不会开启新的线程 -(void)sync_concurrent { // 创建一个全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 同步执行三个任务 dispatch_sync(queue, ^{ NSLog(@"1 %@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2 %@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3 %@",[NSThread currentThread]); }); } |
打印结果:
总结:不开启新线程,主线程执行任务,任务也是顺序执行
4、异步 + 并发队列
// 异步 + 并发队列:同时开启多条线程 -(void)async_concurrent { // 创建一个全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 异步执行三个任务 dispatch_async(queue, ^{ NSLog(@"1 %@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2 %@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3 %@",[NSThread currentThread]); }); } |
打印结果:
总结:开启多条线程,并发执行任务
GCD线程之间的通信
从子线程回到主线程
从子线程回到主线程 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 执行耗时的异步操作... dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程,执行UI刷新操作 }); }); |
线程之间的通信具体实现实例
// 创建 异步 全局并发队列 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 图片的网络路径 NSURL *url = [NSURL URLWithString:@"http://xxx.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
UIImage *image = [UIImage imageWithData:data];
// 回到主线程设置图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
}); |
GCD的其他使用
延迟执行
/** * 延迟执行 */ -(void)delay { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"---我被延迟了3秒执行---"); }); } |
其他延迟执行方法
// method 1 [self performSelector:@selector(do_method) withObject:nil afterDelay:3.0];
// method 2
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self
selector:@selector(do_method) userInfo:nil repeats:NO]; |
只执行一次(用于实现单例模式)
/** * 只执行一次 */ -(void)onlyOnce { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"---我只会被执行一次---"); }); } |
快速遍历
/** * 快速遍历 */ -(void)apply { // 创建一个全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NSInteger count = 10; dispatch_apply(count, queue, ^(size_t index) { NSLog(@"%zd--%@",index,[NSThread currentThread]); }); } |
打印结果:
总结:开启多条线程执行任务,速度远比(for…in…) 遍历快,对于无序的遍历,此方法比较合适
创建线程群组
例如同一个文件分段下载,待所有分段任务下载完成后,合并任务
/** * 创建线程群组 */ -(void)group { // 创建一个全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 创建一个队列组 dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"我是任务-1 %@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"我是任务-2 %@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"我是任务-3 %@",[NSThread currentThread]);
});
// 待群组中的每个任务执行完成后,执行此方法
dispatch_group_notify(group, queue, ^{
NSLog(@"我是终极任务,只有在group里面的任务执行完毕后才执行");
NSLog(@"%@",[NSThread currentThread]);
});
} |
打印结果:
总结:开启多条线程,去执行群组中的任务,当群组内的三个任务执行完毕后,再去执行notify里面的任务
创建屏障线程队列
/** * 创建屏障线程队列 */ -(void)barrier { // 创建一个并发队列 dispatch_queue_t queue = dispatch_queue_create("Mazy", DISPATCH_QUEUE_CONCURRENT); // 创建四个异步任务 dispatch_async(queue, ^{ NSLog(@"我是任务-1 %@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"我是任务-2 %@",[NSThread currentThread]); });
// 创建屏障线程队列
dispatch_barrier_async(queue, ^{
NSLog(@"----barrier-----%@", [NSThread
currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"我是任务-3 %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"我是任务-4 %@",[NSThread currentThread]);
});
} |
打印结果:
总结:会优先执行屏障前面的任务,当屏障前的所有任务执行完毕后,再去执行后面的任
注意:使用sync同步函数往当前串行队列中添加任务,会卡住当前的串行队列
|