什么是GCD?
- GCD全称为Grand Central Dispatch,是libdispatch的市场名称,而libdispatch是Apple的一个库,其为并发代码在iOS和OS X的多核硬件上执行提供支持。
- 确切地说GCD是一套低层级的C API,通过 GCD,开发者只需要向队列中添加一段代码块(block或C函数指针),而不需要直接和线程打交道。
- GCD在后端管理着一个线程池,它不仅决定着你的代码块将在哪个线程被执行,还根据可用的系统资源对这些线程进行管理。
- 这样通过GCD来管理线程,从而解决线程被创建的问题。
GCD的优势
- 易用: GCD 提供一个易于使用的并发模型而不仅仅只是锁和线程,以帮助我们避开并发陷阱,而且因为基于block,它能极为简单得在不同代码作用域之间传递上下文。
- 灵活: GCD 具有在常见模式上(比如锁、单例),用更高性能的方法优化代码,而且GCD能提供更多的控制权力以及大量的底层函数。
- 性能: GCD能自动根据系统负载来增减线程数量,这就减少了上下文切换以及增加了计算效率。
主队列
-
与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。
-
main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。和其它串行队列一样,这个队列中的任务一次只能执行一个。它能保证所有的任务都在主线程执行,而主线程是唯一可用于更新 UI 的线程。
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
NSLog(@"异步主队列");
});
全局队列
- 全局队列是系统提供的可以直接调用的队列,用户不需要创建,可以通过dispatch_get_global_queue这个方法来调用它们。
- 系统为每个程序提供了四种全局队列,这些队列中仅仅通过优先级加以区别,这四种类型分别是高、中(默认)、低、后台。
/** long identifier
* {
* DISPATCH_QUEUE_PRIORITY_HIGH
* DISPATCH_QUEUE_PRIORITY_DEFAULT
* DISPATCH_QUEUE_PRIORITY_LOW
* DISPATCH_QUEUE_PRIORITY_BACKGROUND
* }
*/
dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_sync(defaultQueue, ^{
NSLog(@"同步全局队列");
});
```
# 创建队列
- 我们还可以根据个人具体情况创建属于自己的队列。
- 创建队列有串行队列和并行队列两种,其中串行队列只能单线程操作,并行队列可以多线程操作。
- 而它们的执行方式也有两种:同步执行和异步执行。
// 1. 创建串行队列
dispatch_queue_t createSerialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
// 同步执行
dispatch_sync(createSerialQueue, ^{
NSLog(@"创建串行同步队列");
});
// 2. 创建并行队列
dispatch_queue_t createConcurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
// 异步执行
dispatch_async(createConcurrentQueue, ^{
NSLog(@"创建并行队列");
});
// 挂起队列
dispatch_suspend(createSerialQueue);
// 重挂队列
dispatch_resume(createSerialQueue);
// 变更优先级
dispatch_set_target_queue(createSerialQueue, defaultQueue);
```
单例操作 - 只执行一次的代码块
- 这种方式适合登录、注册等一次性操作,或者应用到静态数据的加载
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"只运行一次哦");
});
延时加载
// 延时 2 秒
double delayInSeconds = 2.0;
// 相对时间
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds);
// 绝对时间
// popTime = [self getDispatchTimeByDate:[NSDate date]];
dispatch_after(popTime, mainQueue, ^{
NSLog(@"延时 2 s 执行");
});
/*
* 获取绝对时间
*/
- (dispatch_time_t)getDispatchTimeByDate:(NSDate *)date
{
double second = 0.0;
struct timespec timespec;
NSTimeInterval interval = [date timeIntervalSinceNow];
timespec.tv_sec = second;
timespec.tv_nsec = modf(interval, &second) * NSEC_PER_SEC;
return dispatch_walltime(×pec, 0);
}
队列组 - 多个依赖关系
- 队列组可以添加多个队列到队列中,而且按添加顺序执行,也相当于多个依赖关系吧
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_group_async(group, defaultQueue, ^{
NSLog(@"执行调度组1");
});
dispatch_group_async(group, defaultQueue, ^{
NSLog(@"执行调度组2");
});
dispatch_group_async(group, defaultQueue, ^{
NSLog(@"执行调度组3");
});
// 只要属于 Dispatch Group 的处理尚未执行结束,就会一直等待,中途不能取消
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_group_notify(group, mainQueue, ^{
NSLog(@"后期添加的 group 队列,在 group 最后执行");
});
```
# 单个依赖关系 - 推荐使用
dispatch_async(defaultQueue, ^{
NSLog(@"先执行我");
});
// 在前面的任务执行结束后它才执行,而且它后面的任务等待其执行完后再执行
dispatch_barrier_async(defaultQueue, ^{
NSLog(@"我是中间执行者哦");
});
dispatch_async(defaultQueue, ^{
NSLog(@"最后执行者");
});
# 同步信号量
- dispatch_semaphore_signal是发送一个信号,自然会让信号总量加1,
- dispatch_semaphore_wait等待信号,当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量-1,根据这样的原理,我们便可以快速的创建一个并发控制来同步任务和有限资源访问控制
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
for (int i = 0; i < 10; i++)
{
// 申请信号量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, defaultQueue, ^{
NSLog(@"申请信号量:%i",i);
sleep(2);
// 释放信号量
dispatch_semaphore_signal(semaphore);
NSLog(@"释放信号量:%i", i);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
# 多个添加队列
// 注意,添加的这 10 个队列同步执行,并等待 queue 全部处理执行结束
unsigned int applyTimes = 5;
dispatch_apply(applyTimes, defaultQueue, ^(size_t i) {
NSLog(@"添加的队列:%zu", i);
});
**个人建议:苹果自己开发或者多人协作开发用 GCD 就足够了,当设计到多个依赖关系时,可以考虑使用 NSOperation 。**
# 参考
[GCD使用三部曲之:基本用法](http://www.jianshu.com/p/d56064507fb8)
网友评论