iOS开发基础36-多线程之GCD
在现代 iOS 开发中,利用多核处理器来提升应用的性能和响应速度是至关重要的。苹果公司推出的 GCD(Grand Central Dispatch),提供了一套强大的并发编程框架,使得开发者能够轻松实现多线程操作。本文将详细介绍 GCD 的基本概念、任务和队列、执行任务的方式、队列的创建、线程间通信、以及其他高级用法及单例模式的实现。
一、基本概念
1. 简介
什么是 GCD
GCD,全称 Grand Central Dispatch,可译为“牛逼的中枢调度器”。它是一套基于 C 语言的底层 API,提供了非常多强大的函数,用来处理并发任务的分发和执行。
GCD 的优势
- 多核优化:GCD 自动利用设备的多核 CPU(如双核、四核等)。
- 线程管理:GCD 自动管理线程的生命周期,包括创建、调度和销毁线程。
- 简化代码:开发者只需定义需要执行的任务,并将其添加到相应的队列,无需编写复杂的线程管理代码。
2. 任务和队列
GCD 中有两个核心概念:任务和队列。
- 任务:具体执行的操作。
- 队列:用于存放任务。
GCD 的使用通常分为两个步骤:
- 定制任务:确定需要执行的操作。
- 将任务添加到队列中:GCD 会按照 FIFO 原则自动将队列中的任务取出,并放到对应的线程中执行。
二、执行任务
1. 执行任务的函数
同步执行任务
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
- queue:队列
- block:任务
异步执行任务
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步和异步的区别
- 同步:只能在当前线程中执行任务,不具备开启新线程的能力。
- 异步:可以在新的线程中执行任务,具备开启新线程的能力。
2. 栅栏函数
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
- 栅栏函数会在前面的任务执行完毕后执行其内部任务,然后再执行其后的任务。
- 栅栏函数必须和普通任务在同一个串行或并发队列中执行,不能用于全局并发队列。
3. 队列的类型
- 并发队列(Concurrent Dispatch Queue):可以让多个任务并发(同时)执行。
- 串行队列(Serial Dispatch Queue):一个任务执行完毕后,再执行下一个任务。
4. 容易混淆的术语
- 同步 vs 异步:影响是否能开启新线程。
- 并发 vs 串行:影响任务执行方式。
三、创建队列
1. 并发队列
通过 dispatch_queue_create
函数创建并发队列:
dispatch_queue_t queue = dispatch_queue_create("com.example.queue", DISPATCH_QUEUE_CONCURRENT);
2. 全局并发队列
使用 dispatch_get_global_queue
函数获取全局并发队列:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
全局并发队列在 iOS 8 以后使用服务质量(QoS)来决定优先级:
- QOS_CLASS_USER_INTERACTIVE:用户交互,优先级最高
- QOS_CLASS_USER_INITIATED:用户需要
- QOS_CLASS_DEFAULT:默认优先级
- QOS_CLASS_UTILITY:工具类,适合耗时操作
- QOS_CLASS_BACKGROUND:后台
3. 串行队列
通过 dispatch_queue_create
函数创建串行队列:
dispatch_queue_t queue = dispatch_queue_create("com.example.serialQueue", NULL); // 或者 DISPATCH_QUEUE_SERIAL
主队列(主线程相关):它是 GCD 自带的一种特殊串行队列,任务在主线程中执行:
dispatch_queue_t queue = dispatch_get_main_queue();
四、线程间通信
从子线程回到主线程:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 处理耗时操作
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
});
五、其他用法
1. 延时执行
使用 GCD
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2 秒后执行的代码
});
2. 一次性执行
保证某段代码在程序运行期间只被执行一次:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 这里的代码只会执行一次
});
3. 快速迭代
使用 dispatch_apply
进行快速迭代:
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index){
// 迭代任务,这段代码会执行 10 次
});
4. 队列组
先分别异步执行两个耗时操作,然后再执行一个回到主线程的操作:
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 第一个耗时操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 第二个耗时操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等到上面两个异步操作都执行完毕后,执行这里的代码
});
六、单例模式
1. 单例模式的作用和使用场合
在程序运行期间,单例模式保证某个类只有一个实例,并且该实例可以方便地被访问,常用于共享一份资源。
2. ARC 中单例模式的实现
定义一个全局的 static 实例
static id _instance;
重写 allocWithZone
方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
提供一个类方法访问实例
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
实现 copyWithZone
方法
- (id)copyWithZone:(struct _NSZone *)zone
{
return _instance;
}
结语
GCD 是 iOS 开发中强大的并发编程工具。通过合理使用 GCD,开发者可以充分利用设备的多核 CPU 提升应用性能,同时简化线程管理逻辑。
将来的你会感谢今天如此努力的你!
版权声明:本文为博主原创文章,未经博主允许不得转载。