GCD (Grand Central Dispatch)
纯C语言,函数强大
GCD的优势
GCD是苹果公司为多核的并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
GCD特点: 性能最好,代码更精简,与系统衔接更好(基于XNU内核))(并发数不可控,任务多时, FIFO队列 顺序执行较难
GCD中有2个核心概念
任务:执行什么操作,Dispatch Source 处理事件
队列:用来存放任务,Dispatch Queue主要是用来管理block
GCD的API全部在libdispatch库中
GCD的使用就2个步骤
定制任务:确定想做的事情
将任务添加到队列中:指定运行方式
GCD会自动将队列中的任务取出,放到对应的线程中执行
任务的取出遵循队列的FIFO原则:先进先出,后进后出 (FIFO)First in first out
队列的类型
1.并发队列(Concurrent Dispatch Queue)
可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
并发功能只有在异步(dispatch_async)函数下才有效
2.串行队列(Serial Dispatch Queue)
让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
3.主队列
特殊的串行队列,代表主线程
GCD中有2个用来执行任务的函数 (queue:队列 block:任务)
1.同步的方式执行任务 (同步:在当前线程中执行)
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
2.异步的方式执行任务 (异步:在另一条线程中执行)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步和异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力
并发和串行决定了任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
串行队列的同步执行和异步执行
以先进先出的方式,顺序调度队列中的任务执行
无论队列中所指定的执行任务函数是同步还是异步,都会等待前一个任务执行完成后,再调度后面的任务
//串行队列
//同步执行
//不开辟线程,顺序执行
//等待sync括号内的执行完之后,执行下一条指令
//串行队列
//异步执行
//开辟一条子线程,顺序执行
//等待async括号内执行完之后,执行下一条代码
并发(并行)队列
以先进先出的方式,并发调度队列中的任务执行
如果当前调度的任务是同步执行的,会等待任务执行完成后,再调度后续的任务
//并发队列
//同步执行
//不开辟线程,顺序执行
//等待sync括号内的执行完之后执行下一条指令
如果当前调度的任务是异步执行的,同时底层线程池有可用的线程资源,会再新的线程调度后续任务的执行
//并发队列
//异步执行
//开辟多条线程,无须执行
//不会等待async括号内的代码执行完才执行下一条指令
主队列,异步任务
不开线程,同步执行
主队列特点:如果主线程正在执行代码暂时不调度任务,等主线程执行结束后在执行任务
主队列又叫 全局串行队列
主队列,同步执行
程序执行不出来(死锁)
主队列:如果主线程正在执行代码,就不调度任务
同步执行:如果第一个任务没有执行,就继续等待第一个任务执行完成,再执行下一个任务此时互相等待,程序无法往下执行(死锁)
//解决主队列死锁
- (void)demo2 {
dispatch_queue_t que =
dispatch_queue_create("111", DISPATCH_QUEUE_CONCURRENT);
// dispatch_queue_t concurrent =
dispatch_async(que, ^{
for (int i = 0; i < 20; i++) {
dispatch_sync(dispatch_get_main_queue(), ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"%@--%d", [NSThread currentThread], i);
});
}
});
}
并发(并行)队列
GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建
使用dispatch_get_global_queue函数获得全局的并发队列
dispatch_queue_t dispatch_get_global_queue(
dispatch_queue_priority_t priority, // 队列的优先级
unsigned long flags); // 此参数暂时无用,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列
全局并发队列的优先级
// iOS8 之前
// dispatch_queue_priority_t
DISPATCH_QUEUE_PRIORITY_HIGH 2 高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT 0 默认优先级
DISPATCH_QUEUE_PRIORITY_LOW (-2) 低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后台优先级
// qos_class_t(iOS8及之后)
QOS_CLASS_USER_INTERACTIVE 0x21, 用户交互(希望最快完成-不能用太耗时的操作)
QOS_CLASS_USER_INITIATED 0x19, 用户期望(希望快,也不能太耗时)
QOS_CLASS_DEFAULT 0x15, 默认(用来底层重置队列使用的,不是给程序员用的)
QOS_CLASS_UTILITY 0x11, 实用工具(专门用来处理耗时操作!)
QOS_CLASS_BACKGROUND 0x09, 后台
QOS_CLASS_UNSPECIFIED 0x00, 未指定,可以和iOS 7.0 适配
结论:如果要适配 iOS 7.0 & 8.0,使用以下代码: dispatch_get_global_queue(0, 0);
全局队列 & 并发队列的区别
1.全局队列
没有名称
无论 MRC & ARC 都不需要考虑释放
日常开发中,建议使用”全局队列”
2.并发队列
有名字,和 NSThread 的 name 属性作用类似
如果在 MRC 开发时,需要使用 dispatch_release(q); 释放相应的对象
dispatch_barrier 必须使用自定义的并发队列
开发第三方框架时,建议使用并发队列
iOS常见的延时执行有2种方式
调用NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒后再调用self的run方法
使用GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后异步执行这里的代码...
});
延时操作
// 1.NSTimer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(demo) userInfo:nil repeats:NO];
// 2.NSObject perform
[self performSelector:@selector(demo) withObject:nil afterDelay:2];
// 3.GCD
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{[self demo];});
队列组
有这么1种需求
首先:分别异步执行2个耗时的操作
其次:等2个异步操作都执行完毕后,再回到主线程执行操作
如果想要快速高效地实现上述需求,可以考虑用队列组
//创建队列组
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的异步操作都执行完毕后,回到主线程...
});
遇到同步往里走一层,遇到一步直接跳过
遇到串行,任务先添加先执行,遇到并行随机执行