• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Harley
博客园    首页    新随笔    联系   管理    订阅  订阅

GCD (I)

GCD是什么?这个概念我就不说了,不会的在百度搜索框搜【GCD】

子线程开启以后占用内存512KB,Main线程开启以后占用内存1M,开销比较大。

 

多线程中的几个概念名词: 任务 和 队列

任务:

就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在 GCD 中是放在 block 中的。执行任务有两种方式:同步执行(sync)和 异步执行(async)。两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。

同步执行(sync):

  • 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
  • 只能在当前线程中执行任务,不具备开启新线程的能力。

异步执行(async):

  • 异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。
  • 可以在新的线程中执行任务,具备开启新线程的能力。

若是这还有理解难度,不仿看看这个🌰:

事件:你要打电话给小明和小白。

同步执行:你打电话给小明的时候,不能同时打给小白,等到给小明打完了,才能打给小白(等待任务执行结束)。而且只能用当前的电话(不具备开启新线程的能力)。
 
而异步执行:你打电话给小明的时候,不等和小明通话结束,还能直接给小白打电话,不用等着和小明通话结束再打(不用等待任务执行结束)。除了当前电话,你还可以使用其他所能使用的电话(具备开启新线程的能力)。
 
注意:异步执行(async)虽然具有开启新线程的能力,但是并不一定开启新线程。这跟任务所指定的队列类型有关(下面会讲)。
 
 

队列(Dispatch Queue)

这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。队列的结构可参考下图:https://www.jianshu.com/p/2d57c72016c6

队列示意图

 

GCD 的使用步骤

  a. 创建一个队列(串行队列或并发队列)

  b. 将任务追加到任务的等待队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)

 

队列的创建/获取

可以使用dispatch_queue_create来创建队列,需要传入两个参数,第一个参数表示队列的唯一标识符,用于 DEBUG,可为空,Dispatch Queue 的名称推荐使用应用程序 ID 这种逆序全程域名;第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL 表示串行队列,DISPATCH_QUEUE_CONCURRENT 表示并发队列。
1     
2 //    串行队列的创建方法
3     dispatch_queue_t queueOne = dispatch_queue_create("GCD_AT_QUEUEONE", DISPATCH_QUEUE_SERIAL);
4     
5 //    并发队列的创建方法
6     dispatch_queue_t queueTwo = dispatch_queue_create("GCD_AT_QUEUETWO", DISPATCH_QUEUE_CONCURRENT)
7     

 

对于串行队列,GCD 提供了的一种特殊的串行队列:主队列(Main Dispatch Queue)特点:

  • 所有放在主队列中的任务,都会放到主线程中执行。
  • 可使用dispatch_get_main_queue()获得主队列。
1 // 主队列的获取方法
2 dispatch_queue_t queue = dispatch_get_main_queue();

对于并发队列,GCD 默认提供了全局并发队列(Global Dispatch Queue)。

  • 可以使用dispatch_get_global_queue来获取。需要传入两个参数。第一个参数表示队列优先级,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT。第二个参数暂时没用,用0即可。
1 // 全局并发队列的获取方法
2 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

 

 

任务的创建

GCD 提供了同步执行任务的创建方法dispatch_sync和异步执行任务创建方法dispatch_async。 

 1 // 同步执行任务创建方法
 2 dispatch_sync(queue, ^{
 3     // 这里放同步执行任务代码
 4 });
 5 
 6 
 7 // 异步执行任务创建方法
 8 dispatch_async(queue, ^{
 9     // 这里放异步执行任务代码
10 });

 

串行队列/并发队列 + 同步执行/异步执行 的组合方式
同步执行 + 并发队列
异步执行 + 并发队列
同步执行 + 串行队列
异步执行 + 串行队列

 

主队类 + 同步执行/异步执行    

1 同步执行 + 主队列
2 异步执行 + 主队列

 

 

开启线程情况:

区别并发队列串行队列主队列
同步(sync) 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 主线程调用:死锁卡住不执行
其他线程调用:没有开启新线程,串行执行任务
异步(async) 有开启新线程,并发执行任务 有开启新线程(1条),串行执行任务 没有开启新线程,串行执行任务

 

GCD 的基本使用

同步执行 + 并发队列

 在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。

 1 - (void)syncConcurrent {
 2     NSLog(@"当前线程是:currentThread-->%@",[NSThread currentThread]);  // 打印当前线程
 3     NSLog(@"syncConcurrent---begin");
 4     
 5     dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
 6     
 7     dispatch_sync(queue, ^{
 8         // 追加任务1
 9         for (int i = 0; i < 2; ++i) {
10             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
11             NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
12         }
13     });
14     
15     dispatch_sync(queue, ^{
16         // 追加任务2
17         for (int i = 0; i < 2; ++i) {
18             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
19             NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
20         }
21     });
22     
23     dispatch_sync(queue, ^{
24         // 追加任务3
25         for (int i = 0; i < 2; ++i) {
26             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
27             NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
28         }
29     });
30     
31     NSLog(@"syncConcurrent---end");
32 }
View Code

 

打印结果:

结论:

a. 所有任务都是在当前线程(主线程)中执行的,没有开启新的线程(同步执行不具备开启新线程的能力)。

b. 所有任务都在打印的syncConcurrent---begin和syncConcurrent---end之间执行的(同步任务需要等待队列的任务执行结束)。

c. 任务按顺序执行的。按顺序执行的原因:虽然并发队列可以开启多个线程,并且同时执行多个任务。但是因为本身不能创建新线程,只有当前线程这一个线程(同步任务不具备开启新线程的能力),所以也就不存在并发。而且当前线程只有等待当前队列中正在执行的任务执行完毕之后,才能继续接着执行下面的操作(同步任务需要等待队列的任务执行结束)。所以任务只能一个接一个按顺序执行,不能同时被执行。

 

同步并发队列的嵌套异步执行

 1 - (void) test1 {
 2     dispatch_queue_t queue = dispatch_queue_create("异步并行", DISPATCH_QUEUE_CONCURRENT);
 3     dispatch_sync(queue, ^{
 4         NSLog(@"-------------》》  1");
 5         dispatch_async(queue, ^{
 6             NSLog(@"~~~~~~~~~~~<<<  2");
 7         });
 8         NSLog(@"------------》》》 3");
 9     });
10 }

 

打印结果:

2018-06-18 16:03:41.925864+0800 BlockTest[1532:176664] -------------》》  1
2018-06-18 16:03:41.926220+0800 BlockTest[1532:176664] ------------》》》 3
2018-06-18 16:03:41.926231+0800 BlockTest[1532:176724] ~~~~~~~~~~~<<<  2

 

结论:同步sync不会开启线程,异步async会开启线程。

 


 

异步执行 + 并发队列

可以开启多个线程,任务交替(同时)执行。

 1 - (void)asyncConcurrent {
 2     NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
 3     NSLog(@"asyncConcurrent---begin");
 4     
 5     dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
 6     
 7     dispatch_async(queue, ^{
 8         // 追加任务1
 9         for (int i = 0; i < 2; ++i) {
10             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
11             NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
12         }
13     });
14     
15     dispatch_async(queue, ^{
16         // 追加任务2
17         for (int i = 0; i < 2; ++i) {
18             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
19             NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
20         }
21     });
22     
23     dispatch_async(queue, ^{
24         // 追加任务3
25         for (int i = 0; i < 2; ++i) {
26             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
27             NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
28         }
29     });
30     
31     NSLog(@"asyncConcurrent---end");
32 }
View Code

 

打印结果:

 

结论:

a. 除了当前线程(主线程),系统又开启了3个线程,并且任务是交替/同时执行的。(异步执行具备开启新线程的能力。且并发队列可开启多个线程,同时执行多个任务)。

b. 所有任务是在打印的syncConcurrent---begin和syncConcurrent---end之后才执行的。说明当前线程没有等待,而是直接开启了新线程,在新线程中执行任务(异步执行不做等待,可以继续执行任务)。

 

问题:

并发队列中异步一定会开辟新线程吗?

1 - (void) test1 {
2     dispatch_queue_t queue = dispatch_queue_create("异步并行", DISPATCH_QUEUE_CONCURRENT);
3     for (int i = 0; i < 100; i ++) {
4         dispatch_async(queue, ^{
5             NSLog(@"%@", [NSThread currentThread]);
6         });
7     }
8 }

 

打印结果:

  1 2018-06-18 15:41:57.581582+0800 BlockTest[1356:162779] <NSThread: 0x604000268a00>{number = 3, name = (null)}
  2 2018-06-18 15:41:57.581675+0800 BlockTest[1356:163016] <NSThread: 0x600000462700>{number = 6, name = (null)}
  3 2018-06-18 15:41:57.581685+0800 BlockTest[1356:162780] <NSThread: 0x600000460240>{number = 4, name = (null)}
  4 2018-06-18 15:41:57.581692+0800 BlockTest[1356:163015] <NSThread: 0x600000461a80>{number = 5, name = (null)}
  5 2018-06-18 15:41:57.581919+0800 BlockTest[1356:162779] <NSThread: 0x604000268a00>{number = 3, name = (null)}
  6 2018-06-18 15:41:57.581956+0800 BlockTest[1356:163016] <NSThread: 0x600000462700>{number = 6, name = (null)}
  7 2018-06-18 15:41:57.582074+0800 BlockTest[1356:162780] <NSThread: 0x600000460240>{number = 4, name = (null)}
  8 2018-06-18 15:41:57.582126+0800 BlockTest[1356:163015] <NSThread: 0x600000461a80>{number = 5, name = (null)}
  9 2018-06-18 15:41:57.582281+0800 BlockTest[1356:163017] <NSThread: 0x6000004661c0>{number = 7, name = (null)}
 10 2018-06-18 15:41:57.582329+0800 BlockTest[1356:163018] <NSThread: 0x6000004603c0>{number = 8, name = (null)}
 11 2018-06-18 15:41:57.582391+0800 BlockTest[1356:163019] <NSThread: 0x60400027a3c0>{number = 9, name = (null)}
 12 2018-06-18 15:41:57.582444+0800 BlockTest[1356:163020] <NSThread: 0x600000469880>{number = 10, name = (null)}
 13 2018-06-18 15:41:57.582496+0800 BlockTest[1356:163021] <NSThread: 0x60000046cd00>{number = 11, name = (null)}
 14 2018-06-18 15:41:57.582551+0800 BlockTest[1356:163022] <NSThread: 0x60400027a0c0>{number = 12, name = (null)}
 15 2018-06-18 15:41:57.582601+0800 BlockTest[1356:163023] <NSThread: 0x60000046d540>{number = 13, name = (null)}
 16 2018-06-18 15:41:57.582645+0800 BlockTest[1356:163024] <NSThread: 0x600000466140>{number = 14, name = (null)}
 17 2018-06-18 15:41:57.582744+0800 BlockTest[1356:163025] <NSThread: 0x60400027a180>{number = 15, name = (null)}
 18 2018-06-18 15:41:57.582798+0800 BlockTest[1356:163026] <NSThread: 0x60000046e840>{number = 16, name = (null)}
 19 2018-06-18 15:41:57.582868+0800 BlockTest[1356:163027] <NSThread: 0x60400027a100>{number = 17, name = (null)}
 20 2018-06-18 15:41:57.582917+0800 BlockTest[1356:163028] <NSThread: 0x60000046e4c0>{number = 18, name = (null)}
 21 2018-06-18 15:41:57.582967+0800 BlockTest[1356:163029] <NSThread: 0x60000046c900>{number = 19, name = (null)}
 22 2018-06-18 15:41:57.583022+0800 BlockTest[1356:163030] <NSThread: 0x60400027a240>{number = 20, name = (null)}
 23 2018-06-18 15:41:57.583115+0800 BlockTest[1356:163031] <NSThread: 0x60000046dc80>{number = 21, name = (null)}
 24 2018-06-18 15:41:57.583149+0800 BlockTest[1356:163032] <NSThread: 0x60000046cc80>{number = 22, name = (null)}
 25 2018-06-18 15:41:57.583225+0800 BlockTest[1356:163033] <NSThread: 0x604000279fc0>{number = 23, name = (null)}
 26 2018-06-18 15:41:57.583292+0800 BlockTest[1356:163034] <NSThread: 0x60000046d980>{number = 24, name = (null)}
 27 2018-06-18 15:41:57.583366+0800 BlockTest[1356:163035] <NSThread: 0x600000469740>{number = 25, name = (null)}
 28 2018-06-18 15:41:57.583427+0800 BlockTest[1356:163036] <NSThread: 0x60400027a380>{number = 26, name = (null)}
 29 2018-06-18 15:41:57.583601+0800 BlockTest[1356:162779] <NSThread: 0x604000268a00>{number = 3, name = (null)}
 30 2018-06-18 15:41:57.583607+0800 BlockTest[1356:163038] <NSThread: 0x60000046cc00>{number = 28, name = (null)}
 31 2018-06-18 15:41:57.583615+0800 BlockTest[1356:163037] <NSThread: 0x6000004697c0>{number = 27, name = (null)}
 32 2018-06-18 15:41:57.583630+0800 BlockTest[1356:163039] <NSThread: 0x60000046d2c0>{number = 29, name = (null)}
 33 2018-06-18 15:41:57.583800+0800 BlockTest[1356:163040] <NSThread: 0x60000046ea00>{number = 30, name = (null)}
 34 2018-06-18 15:41:57.583805+0800 BlockTest[1356:163016] <NSThread: 0x600000462700>{number = 6, name = (null)}
 35 2018-06-18 15:41:57.583954+0800 BlockTest[1356:162780] <NSThread: 0x600000460240>{number = 4, name = (null)}
 36 2018-06-18 15:41:57.584085+0800 BlockTest[1356:163041] <NSThread: 0x60000046e000>{number = 31, name = (null)}
 37 2018-06-18 15:41:57.584089+0800 BlockTest[1356:163015] <NSThread: 0x600000461a80>{number = 5, name = (null)}
 38 2018-06-18 15:41:57.584172+0800 BlockTest[1356:163042] <NSThread: 0x60000046cb40>{number = 32, name = (null)}
 39 2018-06-18 15:41:57.584204+0800 BlockTest[1356:163043] <NSThread: 0x60400027a580>{number = 33, name = (null)}
 40 2018-06-18 15:41:57.584229+0800 BlockTest[1356:163044] <NSThread: 0x60000046db80>{number = 34, name = (null)}
 41 2018-06-18 15:41:57.584380+0800 BlockTest[1356:163017] <NSThread: 0x6000004661c0>{number = 7, name = (null)}
 42 2018-06-18 15:41:57.584499+0800 BlockTest[1356:163045] <NSThread: 0x60000046ebc0>{number = 35, name = (null)}
 43 2018-06-18 15:41:57.584580+0800 BlockTest[1356:163046] <NSThread: 0x60400027a600>{number = 36, name = (null)}
 44 2018-06-18 15:41:57.584611+0800 BlockTest[1356:163047] <NSThread: 0x60000046e540>{number = 37, name = (null)}
 45 2018-06-18 15:41:57.584729+0800 BlockTest[1356:163049] <NSThread: 0x60000046ea80>{number = 39, name = (null)}
 46 2018-06-18 15:41:57.584735+0800 BlockTest[1356:163048] <NSThread: 0x60000046e600>{number = 38, name = (null)}
 47 2018-06-18 15:41:57.584797+0800 BlockTest[1356:163051] <NSThread: 0x60000046e9c0>{number = 41, name = (null)}
 48 2018-06-18 15:41:57.584802+0800 BlockTest[1356:163050] <NSThread: 0x60000046ccc0>{number = 40, name = (null)}
 49 2018-06-18 15:41:57.585064+0800 BlockTest[1356:163052] <NSThread: 0x60000046eb80>{number = 42, name = (null)}
 50 2018-06-18 15:41:57.585113+0800 Blo2018-06-18 15:41:57.585161+0800 BlockTest[1356:163019] <NSThread: 0x60400027a3c0>{number = 9, name = (null)}
 51 ckTest[1356:163018] <NSThread: 0x6000004603c0>{number = 8, name = (null)}
 52 2018-06-18 15:41:57.585199+0800 BlockTest[1356:163020] <NSThread: 0x600000469880>{number = 10, name = (null)}
 53 2018-06-18 15:41:57.585457+0800 BlockTest[1356:163053] <NSThread: 0x60000046ef00>{number = 43, name = (null)}
 54 2018-06-18 15:41:57.585567+0800 BlockTest[1356:163054] <NSThread: 0x60000046d500>{number = 44, name = (null)}
 55 2018-06-18 15:41:57.585703+0800 BlockTest[1356:163056] <NSThread: 0x60000046ed40>{number = 46, name = (null)}
 56 2018-06-18 15:41:57.585652+0800 BlockTest[1356:163055] <NSThread: 0x60000046ed00>{number = 45, name = (null)}
 57 2018-06-18 15:41:57.585865+0800 BlockTest[1356:163057] <NSThread: 0x60000046ecc0>{number = 47, name = (null)}
 58 2018-06-18 15:41:57.585905+0800 BlockTest[1356:163058] <NSThread: 0x60000046edc0>{number = 48, name = (null)}
 59 2018-06-18 15:41:57.585969+0800 BlockTest[1356:163021] <NSThread: 0x60000046cd00>{number = 11, name = (null)}
 60 2018-06-18 15:41:57.586315+0800 BlockTest[1356:163060] <NSThread: 0x60400027a8c0>{number = 50, name = (null)}
 61 2018-06-18 15:41:57.586339+0800 BlockTest[1356:163059] <NSThread: 0x60400027a700>{number = 49, name = (null)}
 62 2018-06-18 15:41:57.586441+0800 BlockTest[1356:163061] <NSThread: 0x60000046eec0>{number = 51, name = (null)}
 63 2018-06-18 15:41:57.586502+0800 BlockTest[1356:163062] <NSThread: 0x60400027a640>{number = 52, name = (null)}
 64 2018-06-18 15:41:57.586525+0800 BlockTest[1356:163063] <NSThread: 0x60000046ec40>{number = 53, name = (null)}
 65 2018-06-18 15:41:57.586714+0800 BlockTest[1356:163065] <NSThread: 0x60400027a680>{number = 55, name = (null)}
 66 2018-06-18 15:41:57.586714+0800 BlockTest[1356:163064] <NSThread: 0x60400027a5c0>{number = 54, name = (null)}
 67 2018-06-18 15:41:57.586850+0800 BlockTest[1356:163066] <NSThread: 0x60000046ef40>{number = 56, name = (null)}
 68 2018-06-18 15:41:57.586925+0800 BlockTest[1356:163067] <NSThread: 0x60000046ef80>{number = 57, name = (null)}
 69 2018-06-18 15:41:57.587156+0800 BlockTest[1356:163068] <NSThread: 0x60000046f040>{number = 58, name = (null)}
 70 2018-06-18 15:41:57.587271+0800 BlockTest[1356:163069] <NSThread: 0x60000046f0c0>{number = 59, name = (null)}
 71 2018-06-18 15:41:57.587402+0800 BlockTest[1356:163070] <NSThread: 0x60000046f140>{number = 60, name = (null)}
 72 2018-06-18 15:41:57.587495+0800 BlockTest[1356:163071] <NSThread: 0x60400027b480>{number = 61, name = (null)}
 73 2018-06-18 15:41:57.587593+0800 BlockTest[1356:163073] <NSThread: 0x60000046f240>{number = 63, name = (null)}
 74 2018-06-18 15:41:57.587605+0800 BlockTest[1356:163072] <NSThread: 0x60000046f200>{number = 62, name = (null)}
 75 2018-06-18 15:41:57.587685+0800 BlockTest[1356:163074] <NSThread: 0x60400027b500>{number = 64, name = (null)}
 76 2018-06-18 15:41:57.587724+0800 BlockTest[1356:163075] <NSThread: 0x60400027b580>{number = 65, name = (null)}
 77 2018-06-18 15:41:57.587835+0800 BlockTest[1356:163076] <NSThread: 0x60400027b600>{number = 66, name = (null)}
 78 2018-06-18 15:41:57.588297+0800 BlockTest[1356:163022] <NSThread: 0x60400027a0c0>{number = 12, name = (null)}
 79 2018-06-18 15:41:57.588469+0800 BlockTest[1356:163023] <NSThread: 0x60000046d540>{number = 13, name = (null)}
 80 2018-06-18 15:41:57.590745+0800 BlockTest[1356:163024] <NSThread: 0x600000466140>{number = 14, name = (null)}
 81 2018-06-18 15:41:57.590941+0800 BlockTest[1356:163025] <NSThread: 0x60400027a180>{number = 15, name = (null)}
 82 2018-06-18 15:41:57.591156+0800 BlockTest[1356:163026] <NSThread: 0x60000046e840>{number = 16, name = (null)}
 83 2018-06-18 15:41:57.591368+0800 BlockTest[1356:163027] <NSThread: 0x60400027a100>{number = 17, name = (null)}
 84 2018-06-18 15:41:57.596669+0800 BlockTest[1356:163028] <NSThread: 0x60000046e4c0>{number = 18, name = (null)}
 85 2018-06-18 15:41:57.596916+0800 BlockTest[1356:163029] <NSThread: 0x60000046c900>{number = 19, name = (null)}
 86 2018-06-18 15:41:57.597929+0800 BlockTest[1356:163030] <NSThread: 0x60400027a240>{number = 20, name = (null)}
 87 2018-06-18 15:41:57.598289+0800 BlockTest[1356:163031] <NSThread: 0x60000046dc80>{number = 21, name = (null)}
 88 2018-06-18 15:41:57.598564+0800 BlockTest[1356:163032] <NSThread: 0x60000046cc80>{number = 22, name = (null)}
 89 2018-06-18 15:41:57.598762+0800 BlockTest[1356:163033] <NSThread: 0x604000279fc0>{number = 23, name = (null)}
 90 2018-06-18 15:41:57.598961+0800 BlockTest[1356:163035] <NSThread: 0x600000469740>{number = 25, name = (null)}
 91 2018-06-18 15:41:57.599146+0800 BlockTest[1356:163034] <NSThread: 0x60000046d980>{number = 24, name = (null)}
 92 2018-06-18 15:41:57.599333+0800 BlockTest[1356:163036] <NSThread: 0x60400027a380>{number = 26, name = (null)}
 93 2018-06-18 15:41:57.599528+0800 BlockTest[1356:162779] <NSThread: 0x604000268a00>{number = 3, name = (null)}
 94 2018-06-18 15:41:57.601326+0800 BlockTest[1356:163038] <NSThread: 0x60000046cc00>{number = 28, name = (null)}
 95 2018-06-18 15:41:57.601627+0800 BlockTest[1356:163039] <NSThread: 0x60000046d2c0>{number = 29, name = (null)}
 96 2018-06-18 15:41:57.601807+0800 BlockTest[1356:163037] <NSThread: 0x6000004697c0>{number = 27, name = (null)}
 97 2018-06-18 15:41:57.601992+0800 BlockTest[1356:163040] <NSThread: 0x60000046ea00>{number = 30, name = (null)}
 98 2018-06-18 15:41:57.602173+0800 BlockTest[1356:163016] <NSThread: 0x600000462700>{number = 6, name = (null)}
 99 2018-06-18 15:41:57.602362+0800 BlockTest[1356:162780] <NSThread: 0x600000460240>{number = 4, name = (null)}
100 2018-06-18 15:41:57.602552+0800 BlockTest[1356:163041] <NSThread: 0x60000046e000>{number = 31, name = (null)}
View Code

 

 

结论:

  从打印结果的线程ID看,只开启了66个线程,说明并发异步执行并不一定会开辟线程。

  在这里,并不能说能开启几条线程,GCD内部会维持一个线程池,根据内核数量来开辟现成的。GCD充分利用了内核,内核数量一般为3-6条,线程越多,内存占用越大。

 


 

 

同步执行 + 串行队列

不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。

 1 - (void)syncSerial {
 2     NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
 3     NSLog(@"syncSerial---begin");
 4     
 5     dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
 6     
 7     dispatch_sync(queue, ^{
 8         // 追加任务1
 9         for (int i = 0; i < 2; ++i) {
10             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
11             NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
12         }
13     });
14     dispatch_sync(queue, ^{
15         // 追加任务2
16         for (int i = 0; i < 2; ++i) {
17             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
18             NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
19         }
20     });
21     dispatch_sync(queue, ^{
22         // 追加任务3
23         for (int i = 0; i < 2; ++i) {
24             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
25             NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
26         }
27     });
28     
29     NSLog(@"syncSerial---end");
30 }
View Code

 DISPATCH_QUEUE_CONCURRENT: 表示并发对列;

 打印结果:

1 2018-03-26 23:01:07.433309+0800 StruggleSwift[2813:112622] currentThread---<NSThread: 0x604000074180>{number = 1, name = main}
2 2018-03-26 23:01:07.433573+0800 StruggleSwift[2813:112622] syncSerial---begin
3 2018-03-26 23:01:09.434949+0800 StruggleSwift[2813:112622] 1---<NSThread: 0x604000074180>{number = 1, name = main}
4 2018-03-26 23:01:11.436135+0800 StruggleSwift[2813:112622] 1---<NSThread: 0x604000074180>{number = 1, name = main}
5 2018-03-26 23:01:13.437605+0800 StruggleSwift[2813:112622] 2---<NSThread: 0x604000074180>{number = 1, name = main}
6 2018-03-26 23:01:15.439129+0800 StruggleSwift[2813:112622] 2---<NSThread: 0x604000074180>{number = 1, name = main}
7 2018-03-26 23:01:17.439636+0800 StruggleSwift[2813:112622] 3---<NSThread: 0x604000074180>{number = 1, name = main}
8 2018-03-26 23:01:19.441061+0800 StruggleSwift[2813:112622] 3---<NSThread: 0x604000074180>{number = 1, name = main}
9 2018-03-26 23:01:19.441352+0800 StruggleSwift[2813:112622] syncSerial---end

结论:

a.   所有任务都是在当前线程(主线程)中执行的,并没有开启新的线程(同步执行不具备开启新线程的能力)。

b.  所有任务都在打印的syncConcurrent---begin和syncConcurrent---end之间执行(同步任务需要等待队列的任务执行结束)。

c.  任务是按顺序执行的(串行队列每次只有一个任务被执行,任务一个接一个按顺序执行,会堵塞当前的线程,对于页面要求高的最好不要这样做)。

 


 

 

异步执行 + 串行队列

会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务

 1 - (void)asyncSerial {
 2     NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
 3     NSLog(@"asyncSerial---begin");
 4     
 5     dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
 6     
 7     dispatch_async(queue, ^{
 8         // 追加任务1
 9         for (int i = 0; i < 2; ++i) {
10             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
11             NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
12         }
13     });
14     dispatch_async(queue, ^{
15         // 追加任务2
16         for (int i = 0; i < 2; ++i) {
17             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
18             NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
19         }
20     });
21     dispatch_async(queue, ^{
22         // 追加任务3
23         for (int i = 0; i < 2; ++i) {
24             [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
25             NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
26         }
27     });
28     
29     NSLog(@"asyncSerial---end");
30 }
View Code

打印结果:

 1 2018-03-26 23:13:24.081039+0800 StruggleSwift[3123:123264] currentThread---<NSThread: 0x608000262380>{number = 1, name = main}
 2 2018-03-26 23:13:24.081287+0800 StruggleSwift[3123:123264] asyncSerial---begin
 3 2018-03-26 23:13:33.516268+0800 StruggleSwift[3123:123264] asyncSerial---end
 4 <-------------------------线程结束-------------------------->
 5 2018-03-26 23:13:36.162848+0800 StruggleSwift[3123:125981] 1---<NSThread: 0x600000464740>{number = 5, name = (null)}
 6 2018-03-26 23:13:39.875777+0800 StruggleSwift[3123:125981] 1---<NSThread: 0x600000464740>{number = 5, name = (null)}
 7 2018-03-26 23:13:44.575848+0800 StruggleSwift[3123:125981] 2---<NSThread: 0x600000464740>{number = 5, name = (null)}
 8 2018-03-26 23:13:46.576325+0800 StruggleSwift[3123:125981] 2---<NSThread: 0x600000464740>{number = 5, name = (null)}
 9 2018-03-26 23:13:50.700796+0800 StruggleSwift[3123:125981] 3---<NSThread: 0x600000464740>{number = 5, name = (null)}
10 2018-03-26 23:13:52.704765+0800 StruggleSwift[3123:125981] 3---<NSThread: 0x600000464740>{number = 5, name = (null)}
View Code                                                                                                                           
number: 线程的ID号;
结论:

开启了一条新线程(异步执行具备开启新线程的能力不会阻塞当前的主线程Main,串行队列只开启一个线程)。

异步一定会开启线程吗?不一定,如这里,异步执行没有开启线程;

记住:同步一定不会开启线程。

串行队列中多个异步,只会开辟一条新线程。

b.  所有任务是在打印的syncConcurrent---begin和syncConcurrent---end之后才开始执行的(异步执行不会做任何等待,可以继续执行任务)。

c.   任务是按顺序执行的(串行队列每次只有一个任务被执行,任务一个接一个按顺序执行)。

下边讲讲刚才我们提到过的特殊队列:主队列。

主队列:GCD自带的一种特殊的串行队列

  • 所有放在主队列中的任务,都会放到主线程中执行
  • 可使用dispatch_get_main_queue()获得主队列

 

异步串行嵌套 

任务简单判别:Block内的代码块称为 任务

 1 - (void) test1 {
 2     dispatch_queue_t queue = dispatch_queue_create("异步串行", DISPATCH_QUEUE_SERIAL);
 3     dispatch_async(queue, ^{ //block1 任务1
 4         NSLog(@"-------------》》  1");
 5         dispatch_async(queue, ^{//block2 任务2
 6             NSLog(@"~~~~~~~~~~~<<<  2");
 7         });
 8         sleep(2);
 9         NSLog(@"------------》》》 3");
10     });
11 }

 

错误认为:1 2 3

打印:

2018-06-18 16:45:25.008760+0800 BlockTest[1811:200571] -------------》》  1
2018-06-18 16:45:27.014469+0800 BlockTest[1811:200571] ------------》》》 3
2018-06-18 16:45:27.014809+0800 BlockTest[1811:200571] ~~~~~~~~~~~<<<  2

 

结论:

打印结果1,2,3称为3个任务。当程序呢运行时,走2不阻塞,走3,任务1(block1)走完后,走2

 

下一篇:GCD(II)

posted @ 2018-03-20 15:43  Harely  阅读(47)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3