iOS基础知识梳理 - 多线程GCD
2019-08-04 本文已影响0人
babyloveblues
什么是GCD
- 全称是Grand Central Dispatch(调度)
- 纯C语言,提供了非常强大的函数
GCD优势
- GCD是苹果公司为多核并行运算提出的解决方案
- GCD会自动利用更多的CPU内核(比如双核、四核)
- GCD会自动管理线程的生命周期(创建线程、任务调度、销毁线程)
- 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
任务和队列
GCD的两个核心概念
任务:执行什么操作
队列:用来存放任务
GCD使用的两个步骤
- 定制任务:确定想做的事情
- 将任务添加到队列中:指定运行方式
-GCD会自动将队列中的任务取出,放到对应的线程执行
-任务的取出遵循队列的FIFO原则:先进先出,后进后出
复杂写法
// 创建任务
dispatch_block_t task = ^{
NSLog(@"task %@", [NSThread currentThread]);
};
// 获取队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 把任务放在队列里面
dispatch_async(queue, task);
简单写法
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"task %@", [NSThread currentThread]);
});
示例 - 使用GCD异步下载图片
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSString *str = @"https://desk-fd.zol-img.com.cn/t_s1280x800c5/g5/M00/02/04/ChMkJ1bKx4qIGTZLAAmjEID8lj0AALH1ADgWvsACaMo983.jpg";
NSURL *url = [NSURL URLWithString:str];
// 获取图片资源
NSData *data = [NSData dataWithContentsOfURL:url];
// 闭包
UIImage *img = [UIImage imageWithData:data];
// 线程通信
dispatch_async(dispatch_get_main_queue(), ^{
self.imgV.image = img;
// 根据图片的大小显示图片
[self.imgV sizeToFit];
[self.scrlView setContentSize:img.size];
});
});
队列的类型
- 并发队列(Concurrent Dispatch Queue)
- 可依然多个任务并发(同时)执行(自动开启多个线程被执行任务)
2.并发功能只有在异步(dispatch_async)函数下才有效
- 可依然多个任务并发(同时)执行(自动开启多个线程被执行任务)
- 串行队列(Serial Dispatch Queue)
- 让任务一个接着一个的执行(一个执行玩了之后再执行下一个任务)
- 主队列
特殊的串行队列,代表主线程
术语梳理
同步 / 异步 / 并发 / 串行
- 同步和异步决定了要不要开启新线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力 - 并发和串行决定了任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
// 串行队列,同步执行
// 不开线程,在当前线程下执行
并发队列 & 串行队列
- (void)demo1{
// 创建串行队列
// 参数一:给队列起个名字
// 参数二:队列的属性
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 20; i++) {
dispatch_sync(serialQueue, ^{
NSLog(@"serialQueue %@", [NSThread currentThread]);
});
}
}
// 串行队列,异步执行
// 开一个线程,任务是有序执行的
- (void)demo2{
// 创建串行队列
// 参数一:给队列起个名字
// 参数二:队列的属性
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 20; i++) {
dispatch_async(serialQueue, ^{
NSLog(@"serialQueue %@", [NSThread currentThread]);
});
}
}
// 并行队列 异步执行
// 开多个线程
// 任务无序执行
- (void)demo3{
// 创建串行队列
// 参数一:给队列起个名字
// 参数二:队列的属性
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 20; i++) {
dispatch_async(concurrentQueue, ^{
NSLog(@"serialQueue %@", [NSThread currentThread]);
});
}
}
// 并行队列 同步执行
// 不开线程,在当前线程下执行
// 任务顺序执行
// 等于串行同步执行
- (void)demo4{
// 创建串行队列
// 参数一:给队列起个名字
// 参数二:队列的属性
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 20; i++) {
dispatch_sync(concurrentQueue, ^{
NSLog(@"serialQueue %@", [NSThread currentThread]);
});
}
}
串行
并行
主队列
// 主队列异步执行
-(void)demo1{
// 得到主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
for (int i = 0; i < 20; i++) {
dispatch_async(mainQueue, ^{
NSLog(@"MAIN QUEUE %@ %d", [NSThread currentThread], i);
});
}
}
// 主队列同步执行
// 这种情况是死锁的,是错的!!!!!!!!!!
// 死锁:主线程下,望住队列添加任务并且同步执行
-(void)demo2{
NSLog(@"begin");
// 得到主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_sync(mainQueue, ^{
NSLog(@"MAIN QUEUE %@", [NSThread currentThread]);
});
NSLog(@"end");
}
对照表
对照表同步执行实战
延时执行
使用GCD的好处就是计时精度高
- (void)demo1{
// // 方式1 timer
// NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(task) userInfo:nil repeats:NO];
//
// //方式2
// [self performSelector:@selector(task) withObject:nil afterDelay:1];
//
// 参数1:延迟的时间 dispatch_time生成时间(以纳秒做单位 精度高)
// 参数2:队列
// 参数3:任务
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"task");
});
NSLog(@"over");
}
队列组
使用队列组下载两个zip文件
- (void)demo1{
NSLog(@"begin");
// 创建队列组
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
[NSThread sleepForTimeInterval:arc4random_uniform(5)];
NSLog(@"LOL1.zip %@", [NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
[NSThread sleepForTimeInterval:arc4random_uniform(5)];
NSLog(@"LOL2.zip %@", [NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"所有任务都下载完成%@", [NSThread currentThread]);
});
}
打开终端Terminal键入man dispatch_group_async