iOS多线程_04_GCD

一、基本概念

1、什么是GCD

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

2、GCD的优势

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

3、任务和队列

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

  任务:执行什么操作

  队列:用来存放任务

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

  <1>定制任务:确定想做的事情

  <2>将任务添加到队列中:

  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是队列的名称,它的作用是在调试的时候,可以看到在某个线程上执行的是哪个队列的任务。
 
 

  输出结果:

  结果说明:

  ① 异步任务 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     }

  输出结果:

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

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     }

  输出结果是:

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

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

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

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

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

(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_sync(q, ^{
 9                 NSLog(@"%@ - %d", [NSThread currentThread], i);
10             });
11         }

输出结果:

跟串行队列,同步任务的输出结果是相同的。

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     }

 

  输出结果:

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

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

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

1     // 1. 获取主队列
2     dispatch_queue_t q = dispatch_get_main_queue();
3     
4     // 3. 不要同步任务(死锁!!!)
5     dispatch_sync(q, ^{
6         NSLog(@"不会输出任何东西");
7     });

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

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

posted @ 2014-08-23 20:00  微博_裕之都  阅读(232)  评论(0编辑  收藏  举报