GCD (I)
GCD是什么?这个概念我就不说了,不会的在百度搜索框搜【GCD】
子线程开启以后占用内存512KB,Main线程开启以后占用内存1M,开销比较大。
多线程中的几个概念名词: 任务 和 队列
任务:
就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在 GCD 中是放在 block 中的。执行任务有两种方式:同步执行(sync)和 异步执行(async)。两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。
同步执行(sync):
- 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
- 只能在当前线程中执行任务,不具备开启新线程的能力。
异步执行(async):
- 异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。
- 可以在新的线程中执行任务,具备开启新线程的能力。
若是这还有理解难度,不仿看看这个🌰:
事件:你要打电话给小明和小白。
队列(Dispatch Queue)
![](https://images2018.cnblogs.com/blog/1161064/201803/1161064-20180320153613517-1150914768.png)
队列示意图
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 的基本使用
同步执行 + 并发队列
在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
打印结果:
结论:
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会开启线程。
异步执行 + 并发队列
可以开启多个线程,任务交替(同时)执行。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
打印结果:
结论:
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 }
打印结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)}
结论:
从打印结果的线程ID看,只开启了66个线程,说明并发异步执行并不一定会开辟线程。
在这里,并不能说能开启几条线程,GCD内部会维持一个线程池,根据内核数量来开辟现成的。GCD充分利用了内核,内核数量一般为3-6条,线程越多,内存占用越大。
同步执行 + 串行队列
不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
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. 任务是按顺序执行的(串行队列
每次只有一个任务被执行,任务一个接一个按顺序执行,会堵塞当前的线程,对于页面要求高的最好不要这样做)。
异步执行 + 串行队列
会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
打印结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)}
开启了一条新线程(异步执行
具备开启新线程的能力不会阻塞当前的主线程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