iOS开发基础36-多线程之GCD

在现代 iOS 开发中,利用多核处理器来提升应用的性能和响应速度是至关重要的。苹果公司推出的 GCD(Grand Central Dispatch),提供了一套强大的并发编程框架,使得开发者能够轻松实现多线程操作。本文将详细介绍 GCD 的基本概念、任务和队列、执行任务的方式、队列的创建、线程间通信、以及其他高级用法及单例模式的实现。

一、基本概念

1. 简介

什么是 GCD

GCD,全称 Grand Central Dispatch,可译为“牛逼的中枢调度器”。它是一套基于 C 语言的底层 API,提供了非常多强大的函数,用来处理并发任务的分发和执行。

GCD 的优势

  • 多核优化:GCD 自动利用设备的多核 CPU(如双核、四核等)。
  • 线程管理:GCD 自动管理线程的生命周期,包括创建、调度和销毁线程。
  • 简化代码:开发者只需定义需要执行的任务,并将其添加到相应的队列,无需编写复杂的线程管理代码。

2. 任务和队列

GCD 中有两个核心概念:任务和队列。

  • 任务:具体执行的操作。
  • 队列:用于存放任务。

GCD 的使用通常分为两个步骤:

  1. 定制任务:确定需要执行的操作。
  2. 将任务添加到队列中: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 提升应用性能,同时简化线程管理逻辑。

posted @ 2015-08-17 21:04  Mr.陳  阅读(328)  评论(0编辑  收藏  举报