GCD总结

有了GCD,我们iOS开发人员确实省事了不少,不用再去对线程有太多的关注。以前拿的是白面的钱,操着白粉的心,就怕几个字眼:死锁,同步,不可控等等。但是现在是拿着白面的钱,操着白面的心,小爷好多事不管了。好了不多说 ,进入主题。

一、概念

Grand ( [ɡrænd],豪华的) Central (['sɛntrəl],中枢的) Dispatch ([dɪ'spætʃ],分派) 的缩写:豪华的(牛逼的中枢分派器)。

是纯C语言写的,不过不要担心指针的残害。虽然是C写的,但是用起来非常方便和容易,用用就知道。

二、GCD的优势

1. GCD是苹果公司为多核的并行运算提出的解决方案

2. GCD会自动利用更多的CPU内核(比如双核、四核)

3. GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

4. 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

三、GCD的核心概念

1. 任务:执行什么操作

2. 队列:用来存放任务

四、GCD的使用步骤

它的使用就分办三个步骤,一定要记住,记住就任你操作,任你装。记不住就改行吧,我差点儿改行了,结果又记住了(多用就好)

1. 定制任务,确定想做的事情

2. 创建队列(获取队列)

3. 将任务添加到队列中。

GCD会自动将队列中的任务取出,放到对应的线程中执行;

任务的取出遵循队列的FIFO原则:先进先出,后进后出。

注意:

程序员要做的是将任务添加到队列就好。然后队列按照程序员指定的方式,调度任务执行。执行方式是我们(小猿来指定的),有同步 和 异步 两种执行方式

同步:一个任务没有结束,就不会执行下一个任务

异步:不用等待任务执行完毕,就会执行下一任务

说到底同步 和 异步 有什么区别呢?

1> 同步:只能在当前线程中执行任务,不具备开启新线程的能力

2> 异步:可以在新的线程中执行任务,具备开启新线程的能力,注意是具备开启新线程能力,不是 “一   定”

刚说不练就是耍流氓,我们来实操一下:

上面说了,GCD的使用,主要为两步,还记得吧?

第一、定制任务(其实就是一个block):

    void(^task)() = ^{

        NSLog(@"%@",[NSThread currentThread]);

    };

第二、创建队列:

    dispatch_queue_t q = dispatch_get_global_queue(0, 0);

第三、将任务添加到队列中,并且会执行

    dispatch_sync(q, task);

完美结束,简单吗?简单吗?

只不过我们经常把上面的步骤合并到一起,就是下面的效果

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        NSLog(@"%@",[NSThread currentThread]);

    });

五、队列分类

上面说过了,会务是要放在队列去执行。那么队列有哪几类呢?有两类。

1. 串行队列(SerialDispatch Queue)

让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

2. 并行队列(ConcurrentDispatch Queue)

并行队列可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并且,并且,并且 ,并发功能只有在异步(dispatch_async)函数下 异步,异步 函数下才有效。为什么呢?大家想想。

说到这里我觉得有必要强调几个术语:同步,异步,并行,串行。大家有没有懵的?有没有概念混淆的?

1. 同步和异步主要影响:能不能开启新的线程

同步:只是在当前线程中执行任务,不具备开启新线程的能力

异步:可以在新的线程中执行任务,具备开启新线程的能力,是具备开启,不是一定开启

2. 并发和串行主要影响:任务的执行方式

并发:允许多个任务并发(同时)执行

六、创建队列

使用 dispatch_queue_create 函数创建队列

1. 创建并行队列:

A. dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", DISPATCH_QUEUE_CONCURRENT);

参数1:队列名称

参数2:队列的类型:DISPATCH_QUEUE_CONCURRENT表示并行,DISPATCH_QUEUE_SERIAL表示串行,或者这个参数写NULL也表示串行

B. 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);

其实参数1严格上来说涉及到系统的适配:在iOS8及上版本称作:服务质量,iOS7称作:高度优先有级。不同系统传不同参数。如下

iOS 8 服务质量

    QOS_CLASS_USER_INTERACTIVE    用户交互(希望线程快速被执行,不要用好使的操作)

    QOS_CLASS_USER_INITIATED      用户需要的(同样不要使用耗时操作)

    QOS_CLASS_DEFAULT            默认的(给系统来重置队列的)

    QOS_CLASS_UTILITY            使用工具(用来做耗时操作)

    QOS_CLASS_BACKGROUND          后台

    QOS_CLASS_UNSPECIFIED        没有指定优先级

    iOS 7  调度的优先级

    - DISPATCH_QUEUE_PRIORITY_HIGH 2              高优先级

    - DISPATCH_QUEUE_PRIORITY_DEFAULT 0            默认优先级

    - DISPATCH_QUEUE_PRIORITY_LOW (-2)            低优先级

    - DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后台优先级

由于 默认模式 在两种模式的宏定义中都是0,所以我们一般都传了0,可以直接适配系统版本。

但是在注意,注意,注意;

 不管什么系统版本都不要选择 后台 模式 ,不然此线程会调用特别慢,慢到您想放弃iOS,直接转行捡垃圾去。不信你试试。

2. 创建串行队列

GCD中获得串行有2种途径:

A. 使用 dispatch_queue_create 函数创建串行队列

创建串行队列(队列类型传递NULL或者DISPATCH_QUEUE_SERIAL)

dispatch_queue_t queue = dispatch_queue_create("com.xxx.xxx", NULL);

B. 使用主队列(跟主线程相关联的队列)

主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行

使用 dispatch_get_main_queue() 获得主队列

dispatch_queue_t queue = dispatch_get_main_queue();

七、一副图看清所有GCD关系:


GCD总结_第1张图片

注:图片来源于”潭州课堂“,一个让你受益匪浅的课堂,大家可以去学习下,其实不止图片,这些内容也是我对课程的一个总结。

最后再来补充两点:

1,全局队列 & 并发队列

    大家知道,全局队列本质也是并发队列,那我们在项目中要使用并发队列时候,具体用哪一个哪?

    个人认为,当业务比较复杂时,最好使用手动创建并发队列,原因是,如果内部出现问题我们可以快速定位到是哪个队

     列(创建时有队列名称)的任务出了问题,如果下图:


GCD总结_第2张图片

我想大家见过这样的崩溃吧?不是崩在具体某一行代码上,面是上面这样的情况。虽然我们根据 1 一眼能够看出来是 数组越界 导致的,但是如果项目比较大,你知道是哪个数组吗?知道吗?知道吗?。但是,我们如果使用了手动创建的队列,那么可以根据 2 得到,是“xiaoyuancai”这个队列的任务出了问题,从而快速定位,484(是不是) 484 ?

当然也不是说全局队列没用,当我们业务简单,那完全可以使用全局队列。

2,并发队列 & 串行队列

    并发队列的优势:并发,能够调度多个线程,执行效率高。但是对于用于而言会觉得太 费电 ,手机太 烫  

    串行队列的优势:那当然省电了。不过缺点也明显:串行队列:一个一个执行,执行效率低。

差不多了,至于GCD其它操作再起一篇来介绍。大家准备好来吐槽!!!

你可能感兴趣的:(GCD总结)