iOS多线程_04_GCD

一、基本概念

1、什么是GCD

  • 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
  • 纯C语言,提供了非常多强大的函数

2、GCD的优势

  • GCD是苹果公司为多核的并行运算提出的解决方案
  • GCD会自动利用更多的CPU内核(比如双核、四核)
  • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
  • 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

3、任务和队列

(1)GCD中有2个核心概念

  任务:执行什么操作

  队列:用来存放任务

(2)GCD的使用就2个步骤

  定制任务

  确定想做的事情

(3)将任务添加到队列中

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

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

二、执行任务

1、执行任务

(1)GCD中有2个用来执行任务的函数

  用同步的方式执行任务

  dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

  queue:队列

  block:任务

  用异步的方式执行任务

  dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

(2)同步和异步的区别

  同步:在当前线程中执行

  异步:在另一条线程中执行

2、队列的类型

  GCD的队列可以分为2大类型

(1)并行队列(Concurrent Dispatch Queue)

  可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)

  并发功能只有在异步(dispatch_async)函数下才有效

(2)串行队列(Serial Dispatch Queue)

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

3、比较容易混淆的术语:同步、异步、并发、串行

(1)同步和异步决定了要不要开启新的线程

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

  异步:在新的线程中执行任务,具备开启新线程的能力

(2)并发和串行决定了任务的执行方式

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

  串行:一个任务执行完毕后,再执行下一个任务

三、“串行队列”、“并行队列”、“全局队列”和“主队列

  DISPATCH_QUEUE_SERIAL   串行队列 与NULL等效

  DISPATCH_QUEUE_CONCURRENT 并行队列

1、串行队列

(1)第一种:串行队列,异步任务

 1     // 1.串行队列

 2     // 在使用GCD的时候,先敲dispatch

 3     // 在C语言中,定义对象通常是以 _t 或者 Ref 结尾的

 4     // dispatch_queue_t q = dispatch_queue_create("ios", DISPATCH_QUEUE_SERIAL);

 5     dispatch_queue_t q = dispatch_queue_create("ios", NULL);

 6     

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

 8     

 9     // 2. 异步任务 async,能够开线程

10     // 串行队列中,异步任务最多只能开一条线程,所有任务顺序执行!

11     // 串行队列,异步任务,在多线程中,是斯坦福大学最推荐的一种多线程方式!

12     // 优点:将任务放在其他线程中工作,每个任务顺序执行,便于调试

13     // 缺点:并发能力不强,最多只能使用一条子线程!

14     for (int i = 0; i < 10; i++) {

15         dispatch_async(q, ^{

16             NSLog(@"%@ - %d", [NSThread currentThread], i);

17         });

18     }
   ios是队列的名称,它的作用是在调试的时候,可以看到在某个线程上执行的是哪个队列的任务。
iOS多线程_04_GCD
 
 

  输出结果:

iOS多线程_04_GCD

  结果说明:

  ① 异步任务 async 能够开线程

  ② 串行队列中,异步任务最多只能开一条线程,所有任务顺序执行!

  ③ 串行队列,异步任务,在多线程中,是斯坦福大学最推荐的一种多线程方式!

  优点:将任务放在其它线程中工作,每个任务顺序执行,便于调试

  缺点:并发能力不强,最多只能使用一条子线程!

(2)第二种:串行队列,同步任务

1     // 2. 同步任务 sync(没用处)

2     for (int i = 0; i < 10; i++) {

3         dispatch_sync(q, ^{

4             NSLog(@"%@ - %d", [NSThread currentThread], i);

5         });

6     }

  输出结果:

iOS多线程_04_GCD

  从输出结果可以看出,串行队列,同步任务,是在主线程顺序执行的,默认就是顺序执行的,所以这个没什么用。

2、并行队列

(1)第一种:并行队列,异步任务

 1     // 1.并行队列

 2     dispatch_queue_t q = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);

 3     

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

 5     

 6     // 2.异步任务

 7     for (int i = 0; i < 10; i++) {

 8         dispatch_async(q, ^{

 9             NSLog(@"%@ - %d", [NSThread currentThread], i);

10         });

11     }

  输出结果是:

iOS多线程_04_GCD

  ① 并行队列,异步任务,开启了多条子线程执行。

  ② 异步任务,会在多条线程上工作,具体开多少条线程,由系统决定

  ③ 仍然是按照任务添加到队列中的顺序被调度,只是执行先后可能会有差异!

  ④ 能够将耗时的操作,放到子线程中工作

  ⑤ 与串行队列异步任务相比,并发性能更好!但是执行的先后顺序,不固定

(2)第二种,并行队列,同步任务

 1     // 1.并行队列

 2     dispatch_queue_t q = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);

 3     

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

 5     

 6     // 2.异步任务

 7     for (int i = 0; i < 10; i++) {

 8         dispatch_async(q, ^{

 9             NSLog(@"%@ - %d", [NSThread currentThread], i);

10         });

11     }

12 

13     // 3.同步任务

14     for (int i = 0; i < 10; i++) {

15         dispatch_sync(q, ^{

16             NSLog(@"%@ - %d", [NSThread currentThread], i);

17         });

18     }

  从下图可以看出,并行队列的同步任务是在主队列上依次执行的:

iOS多线程_04_GCD

  如果,把同步任务放在异步任务之前,会发生什么呢?

iOS多线程_04_GCD

  输出结果说明,只有在同步任务执行完成之后,才会执行异步任务,这在开发中只有一种情况有价值,其它用途都是捣乱。

  并行队列,同步任务的价值:在用户登录的时候,只有用户登录成功,才会执行后面的操作。而且因为是异步任务,开启了子线程,所以在用户登录过程中,还是可以进行其它操作(比如取消登录,关闭操作等等)。

3、全局队列

  全局队列又叫全局并行队列全局并发队列,所以全局队列是并行队列

 1     // 1. 获取全局队列(与自定义并行队列的区别就是名字显示,其他都一样)

 2     dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

 3     // 使用全局队列,不需要考虑共享的问题

 4     

 5     // 3. 同步任务

 6     for (int i = 0; i < 10; i++) {

 7         dispatch_sync(q, ^{

 8             NSLog(@"%@ - %d", [NSThread currentThread], i);

 9         });

10     }

11     

12     // 2. 异步任务

13     for (int i = 0; i < 10; i++) {

14         dispatch_async(q, ^{

15             NSLog(@"%@ - %d", [NSThread currentThread], i);

16         });

17     }

  因为是 DISPATCH_QUEUE_PRIORITY_DEFAULT(默认的优先级)输出结果跟在自定义并行队列里的结果一样

  全局队列使用更普遍一些,因为使用起来简单

  不需要考虑共享问题:指MRC中,自定义并行队列 dispatch_queue_t q = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);需要自己释放队列dispatch_release(q);

  因此,无论是ARC还是MRC,使用默认优先级的全局队列不用考虑共享问题。

  唯一跟自定义并行队列的区别是,队列名字不同

  

4、主队列

  是专门在主线程上工作的队列,即专门调度任务在主队列上执行

(1)主队列,异步任务

1     // 1. 获取主队列

2     dispatch_queue_t q = dispatch_get_main_queue();

3     

4     // 2. 异步任务,在主线程上依次顺序执行

5     for (int i = 0; i < 10; i++) {

6         dispatch_async(q, ^{

7             NSLog(@"%@ - %d", [NSThread currentThread], i);

8         });

9     }

 

  输出结果:

iOS多线程_04_GCD

  输出结果说明,主队列上异步任务依次顺序执行,跟串行队列的异步任务不同的是,没有开启子线程。

  所以,异步任务是以异步的方式执行,不一定在哪个线程上。有可能在主线程上,也有可能在子线程上。

(2)主队列,同步任务(千万不能使用

1     // 1. 获取主队列

2     dispatch_queue_t q = dispatch_get_main_queue();

3     

4     // 3. 不要同步任务(死锁!!!)

5     dispatch_sync(q, ^{

6         NSLog(@"不会输出任何东西");

7     });

  不会输出任何东西,没有任何反应,这种情况叫任务死锁

  因为,应用程序已启动,就会建立一个线程,这个线程被称为主线程。而主队列的同步任务会一直等待主线程执行完了,只有程序挂了,主线程才结束,根本就不会执行主队列的同步任务。

你可能感兴趣的:(多线程)