CGD简介
什么是GCD
- GCD的全称是Grand Central Dispatch,可以把它翻译为"牛逼的中枢调度器"。😉
- 纯C语言,提供了很多强大的函数
GCD的优势
- GCD是苹果公司为解决多核的并行运算而提出的解决方案
- CGD会自动利用更多的CPU内容(如双核、四核...)
- GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
- 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
GCD中的概念和使用步骤
2个核心概念
任务:
执行的什么操作,用block代码块的形式创建
队列:
是用来陈放任务的载体,负责调度任务;队列有两种类型:
- 串行队列:一个接一个的调度任务 (
DISPATCH_QUEUE_SERIAL
、dispatch_get_main_queue()
) - 并行队列:可以同时调度多个任务 (
DISPATCH_QUEUE_CONCURRENT
、dispatch_get_global_queue(0,0)
)
使用步骤(2步)
定制任务
确定想要执行的任务
将任务添加到队列中
- GCD会自动将队列中的任务取出,放到对应的线程中执行
- 任务的取出遵循队列的FIFO原则:先进先出
在这个过程中,我们需要做的就是:将任务以指定的方式(同步/异步)添加到队列中,队列就会按照我们指定的方式调度任务。
- 同步:一个任务没有结束,就不会执行下一个任务
- 异步:不用等当前任务执行完毕,就会去线程池开辟一个子线程,执行下一个任务
- 线程池:在GCD的底层有一个线程池,负责创建线程、分配线程、销毁线程
我的理解
队列、任务、线程池如上图,GCD主要由任务、队列、执行方式三个部分组成,又由于队列类型(串行/并行)、执行方式(同步/异步)的不同,可以两两组合,从而出现四种情况,后面会一一通过代码来实现。这里主要说明的是:
-
对于串行队列
当任务执行时,必须要等当前任务执行完成后才能去队列中拿下一个任务,所以不管是同步执行,还是异步执行,都是按照顺序执行的 -
对于并行队列
当任务执行时,不用等当前任务执行完毕就可以去队列拿下一个任务,此时若是: - 同步执行
由于只有同步执行不会去现成池拿新的线程,即使你拿到多个任务,也只能在当前线程排队等待,等前一个任务执行完毕后,才能执行下一个,所以还是按照顺序执行
- 同步执行
- 异步执行
如果在并行队列异步执行任务的话,首先会去队列中拿到多个任务,并且会去线程池中获取子线程,所以会出现多个任务并发执行的情况,这时候任务的执行顺序是不确定的,而我们用GCD大部分的场景都是这种情况
- 异步执行
下面,通过代码,来依次验证这些情况。
GCD实战
创建队列
所有的队列都是dispatch_queue_t
类型,常用创建队列通常有三种方法,其中有两种是系统提供的:
-
主队列
通过dispatch_get_main_queue()
方法返回一个dispatch_queue_t
对象,这是一个串行队列,即该队列中的所有任务都是顺序执行的。 -
全局队列
这个队列通过dispatch_get_global_queue(long identifier, unsigned long flags)
函数获取,对于这个函数有两个参数: -
identifier
这个参数是表示一个优先级的,但是在iOS 8之前和之后其参数类型不太一样
iOS 8
及之后版本表示的含义是:服务质量,其类型如下:
-
QOS_CLASS_USER_INTERACTIVE 用户交互(希望线程快速被执行,不要用好使的操作)
QOS_CLASS_USER_INITIATED 用户需要的(同样不要使用耗时操作)
QOS_CLASS_DEFAULT 默认的(给系统来重置队列的)
QOS_CLASS_UTILITY 使用工具(用来做耗时操作)
QOS_CLASS_BACKGROUND 后台
QOS_CLASS_UNSPECIFIED 没有指定优先级
而在iOS 8
之前版本表示的含义是:调度的优先级,其类型如下:
DISPATCH_QUEUE_PRIORITY_HIGH 2 高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT 0 默认优先级
DISPATCH_QUEUE_PRIORITY_LOW (-2) 低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后台优先级
提示
不要选择BACKGROUND
优先级,服务质量,因为线程执行会慢到令人发指!!!体现在任务调度次数少,执行时间短。通常基本都使用默认的,填入0
-
flags
: 是一个预留参数,同常填0
-
- 自己创建一个队列
GCD提供了一个可以自己创建队列的函数:dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t _Nullable attr#>)
函数,使用此函数可以创建一个自定义的队列。 -
label
参数: 是一个队列标签,即队列名,通常给一个字符串
-
-
attr
参数: 是队列属性;系统提供了两个宏:DISPATCH_QUEUE_SERIAL
或者NULL
因为这个宏就是NULL
,表示串行队列;DISPATCH_QUEUE_CONCURRENT
:表示并行队列。
-
添加任务
添加任务:将任务以指定的执行方式添加到队列中去;它的方式有两种:
- 同步执行:
即只会在当前线程中执行任务,无法去线程池中获取新的线程
/**
*queue: 添加到的队列
*block:就放我们需要执行的任务
*/
dispatch_sync(dispatch_queue_t _Nonnull queue, ^{
//you todo
});
- 异步执行:
即可以去线程池中获取新的线程,其参数含义和同步执行的相同,只是函数名换成了dispatch_async
dispatch_async(dispatch_queue_t _Nonnull queue, ^{
//you todo
})
介绍完了基本函数语法,下面来用代码实现上述所说的4中情况。
串行队列同步执行
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self gcdBase1];
}
- (void)gcdBase1 {
dispatch_queue_t queue = dispatch_queue_create(myQueue, DISPATCH_QUEUE_SERIAL);
for (NSInteger i = 0; i < 10; i ++) {
dispatch_sync(queue, ^{
NSLog(@"%ld ------ %@", (long)i, [NSThread currentThread]);
});
}
}
我在touchesBegan
方法中,串行队列中以同步执行的方法添加了10个NSLog
任务,当点击屏幕时,控制台获得以下输出:
2017-01-10 21:54:58.609 GCD-01[13124:1295897] 0 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.609 GCD-01[13124:1295897] 1 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.609 GCD-01[13124:1295897] 2 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.610 GCD-01[13124:1295897] 3 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.610 GCD-01[13124:1295897] 4 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.610 GCD-01[13124:1295897] 5 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.610 GCD-01[13124:1295897] 6 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.611 GCD-01[13124:1295897] 7 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.611 GCD-01[13124:1295897] 8 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
2017-01-10 21:54:58.611 GCD-01[13124:1295897] 9 ------ <NSThread: 0x600000079e00>{number = 1, name = main}
由结果可以看出,不会开启线程,并且任务是顺序执行的,符合预期,并且无论你点击多少次,结果都不会改变。
串行队列异步执行
这次我在touchesBegan
方法中执行以下任务,在一个串行队列中,添加10个异步任务,并且在任务添加后,打印一句I am here
,猜猜这次的打印结果会是怎么样的?????
- (void)gcdBase2 {
dispatch_queue_t queue = dispatch_queue_create(myQueue, DISPATCH_QUEUE_SERIAL);
for (NSInteger i = 0; i < 10; i ++) {
dispatch_async(queue, ^{
NSLog(@"%ld ------ %@", (long)i, [NSThread currentThread]);
});
}
NSLog(@"I am here");
}
在模拟器中点击屏幕,获得以下结果:
2017-01-10 22:06:01.703 GCD-01[13385:1322583] I am here <NSThread: 0x600000066a40>{number = 1, name = main}
2017-01-10 22:06:01.703 GCD-01[13385:1322734] 0 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.703 GCD-01[13385:1322734] 1 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.703 GCD-01[13385:1322734] 2 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.703 GCD-01[13385:1322734] 3 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.704 GCD-01[13385:1322734] 4 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.704 GCD-01[13385:1322734] 5 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.704 GCD-01[13385:1322734] 6 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.705 GCD-01[13385:1322734] 7 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.705 GCD-01[13385:1322734] 8 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
2017-01-10 22:06:01.705 GCD-01[13385:1322734] 9 ------ <NSThread: 0x61800006b0c0>{number = 3, name = (null)}
由以上结果可以看出,异步执行,会创建新的线程去执行任务,在串行队列中,由于每次只能拿一个任务,所以任务是按照FIFO
顺序执行的。这里的I am here
位置不一定一直处于第一位,但是肯定是靠前的。但是我试了很多次,都是第一位,尴尬。。。
并行队列同步执行
我在touchesBegan
方法中执行以下任务;将队列类型换成DISPATCH_QUEUE_CONCURRENT
,即并行队列,然后添加同步任务
- (void)gcdBase3 {
dispatch_queue_t queue = dispatch_queue_create(myQueue, DISPATCH_QUEUE_CONCURRENT);
for (NSInteger i = 0; i < 10; i ++) {
dispatch_sync(queue, ^{
NSLog(@"%ld ------ %@", (long)i, [NSThread currentThread]);
});
}
NSLog(@"I am here %@", [NSThread currentThread]);
}
点击屏幕获取打印:
2017-01-10 22:12:34.551 GCD-01[13537:1337073] 0 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.551 GCD-01[13537:1337073] 1 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.551 GCD-01[13537:1337073] 2 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.552 GCD-01[13537:1337073] 3 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.552 GCD-01[13537:1337073] 4 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.552 GCD-01[13537:1337073] 5 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.552 GCD-01[13537:1337073] 6 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.553 GCD-01[13537:1337073] 7 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.553 GCD-01[13537:1337073] 8 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.553 GCD-01[13537:1337073] 9 ------ <NSThread: 0x6180000764c0>{number = 1, name = main}
2017-01-10 22:12:34.553 GCD-01[13537:1337073] I am here <NSThread: 0x6180000764c0>{number = 1, name = main}
结果:由打印信息可以看出,同步任务不会创建新的线程,由于只有一个线程,即使是并行队列可以同时获取多个任务,最终也会按照顺序执行,因为只有一条线程。
并行队列异步执行
- (void)gcdBase4 {
dispatch_queue_t queue = dispatch_queue_create(myQueue, DISPATCH_QUEUE_CONCURRENT);
for (NSInteger i = 0; i < 10; i ++) {
dispatch_async(queue, ^{
NSLog(@"%ld ------ %@", (long)i, [NSThread currentThread]);
});
}
NSLog(@"I am here %@", [NSThread currentThread]);
}
这次我多次点击屏幕时,获得以下输出:
2017-01-10 22:18:15.768 GCD-01[13664:1350605] I am here <NSThread: 0x60000006bcc0>{number = 1, name = main}
2017-01-10 22:18:15.768 GCD-01[13664:1350805] 0 ------ <NSThread: 0x618000070700>{number = 3, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351252] 1 ------ <NSThread: 0x61800006bf80>{number = 4, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351253] 2 ------ <NSThread: 0x610000073880>{number = 5, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351254] 3 ------ <NSThread: 0x61800006afc0>{number = 6, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351255] 4 ------ <NSThread: 0x6000000725c0>{number = 7, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351256] 5 ------ <NSThread: 0x61800006a2c0>{number = 8, name = (null)}
2017-01-10 22:18:15.769 GCD-01[13664:1351257] 6 ------ <NSThread: 0x610000073540>{number = 9, name = (null)}
2017-01-10 22:18:15.769 GCD-01[13664:1351258] 7 ------ <NSThread: 0x618000070480>{number = 10, name = (null)}
2017-01-10 22:18:15.769 GCD-01[13664:1350805] 8 ------ <NSThread: 0x618000070700>{number = 3, name = (null)}
2017-01-10 22:18:15.769 GCD-01[13664:1351252] 9 ------ <NSThread: 0x61800006bf80>{number = 4, name = (null)}
2017-01-10 22:18:24.114 GCD-01[13664:1350605] I am here <NSThread: 0x60000006bcc0>{number = 1, name = main}
2017-01-10 22:18:24.115 GCD-01[13664:1351637] 1 ------ <NSThread: 0x610000073940>{number = 12, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351259] 0 ------ <NSThread: 0x60800006e080>{number = 11, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351638] 2 ------ <NSThread: 0x6180000705c0>{number = 13, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351639] 3 ------ <NSThread: 0x61000006f240>{number = 14, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351641] 4 ------ <NSThread: 0x61800006c080>{number = 15, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351643] 5 ------ <NSThread: 0x600000071f80>{number = 16, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351640] 7 ------ <NSThread: 0x600000072ac0>{number = 18, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351644] 6 ------ <NSThread: 0x618000070500>{number = 17, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351637] 8 ------ <NSThread: 0x610000073940>{number = 12, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351647] 9 ------ <NSThread: 0x610000073540>{number = 19, name = (null)}
2017-01-10 22:18:26.446 GCD-01[13664:1350605] I am here <NSThread: 0x60000006bcc0>{number = 1, name = main}
2017-01-10 22:18:26.446 GCD-01[13664:1351647] 0 ------ <NSThread: 0x610000073540>{number = 19, name = (null)}
2017-01-10 22:18:26.446 GCD-01[13664:1351637] 1 ------ <NSThread: 0x610000073940>{number = 12, name = (null)}
2017-01-10 22:18:26.446 GCD-01[13664:1351644] 2 ------ <NSThread: 0x618000070500>{number = 17, name = (null)}
2017-01-10 22:18:26.446 GCD-01[13664:1351640] 3 ------ <NSThread: 0x600000072ac0>{number = 18, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351643] 4 ------ <NSThread: 0x600000071f80>{number = 16, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351641] 5 ------ <NSThread: 0x61800006c080>{number = 15, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351639] 6 ------ <NSThread: 0x61000006f240>{number = 14, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351638] 7 ------ <NSThread: 0x6180000705c0>{number = 13, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351259] 8 ------ <NSThread: 0x60800006e080>{number = 11, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351646] 9 ------ <NSThread: 0x610000073d80>{number = 20, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351646] 0 ------ <NSThread: 0x610000073d80>{number = 20, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1350605] I am here <NSThread: 0x60000006bcc0>{number = 1, name = main}
2017-01-10 22:18:26.598 GCD-01[13664:1351259] 1 ------ <NSThread: 0x60800006e080>{number = 11, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351638] 2 ------ <NSThread: 0x6180000705c0>{number = 13, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351639] 3 ------ <NSThread: 0x61000006f240>{number = 14, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351641] 4 ------ <NSThread: 0x61800006c080>{number = 15, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351643] 5 ------ <NSThread: 0x600000071f80>{number = 16, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351640] 6 ------ <NSThread: 0x600000072ac0>{number = 18, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351644] 7 ------ <NSThread: 0x618000070500>{number = 17, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351637] 8 ------ <NSThread: 0x610000073940>{number = 12, name = (null)}
2017-01-10 22:18:26.599 GCD-01[13664:1351649] 9 ------ <NSThread: 0x61800006f680>{number = 21, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351637] 1 ------ <NSThread: 0x610000073940>{number = 12, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351649] 0 ------ <NSThread: 0x61800006f680>{number = 21, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351644] 2 ------ <NSThread: 0x618000070500>{number = 17, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1350605] I am here <NSThread: 0x60000006bcc0>{number = 1, name = main}
2017-01-10 22:18:26.734 GCD-01[13664:1351640] 3 ------ <NSThread: 0x600000072ac0>{number = 18, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351643] 4 ------ <NSThread: 0x600000071f80>{number = 16, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351641] 5 ------ <NSThread: 0x61800006c080>{number = 15, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351639] 6 ------ <NSThread: 0x61000006f240>{number = 14, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351638] 7 ------ <NSThread: 0x6180000705c0>{number = 13, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351259] 8 ------ <NSThread: 0x60800006e080>{number = 11, name = (null)}
2017-01-10 22:18:26.735 GCD-01[13664:1351646] 9 ------ <NSThread: 0x610000073d80>{number = 20, name = (null)}
结果分析: 由多次点击结果可以确定,异步任务,开启了新线程,并发执行能够拿到多个任务,所以上面会出现任务执行顺序不一致,并且I am here
的位置,也可以确定主线程没有被影响。
一个模拟项目中的同步任务
在这里我模拟一个实际开发流程:比如在一个读书的APP中,通常会出现付费下载的情况,当用户在游客模式去浏览,发现到自己喜欢的书籍时,去点击下载,这时候就需要走 登录 -> 支付 -> 下载,这就是一个同步任务,这里有很多网络请求,属于耗时操作,通常我们都在子线程中去完成。在这个任务中,我们将设置一下流程,用户必须先登录,然后同时执行支付和下载任务。对此,实现以下代码:
- (void)gcdSyncTask {
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create(myQueue, DISPATCH_QUEUE_CONCURRENT);
//同步添加 用户登录 任务
dispatch_sync(queue, ^{
NSLog(@"用户登录");
});
//异步添加 支付任务 可以在子线程中执行
dispatch_async(queue, ^{
NSLog(@"支付任务");
});
//异步添加 下载任务 可以在子线程中执行
dispatch_async(queue, ^{
NSLog(@"下载任务");
});
}
当点击屏幕获得以下打印:经过多次点击都可以发现,用户登录永远都先执行的,只有用户登录完成后,才会去执行支付和下载任务。实际情况,任务的执行会更加耗时,那么支付和下载的完成顺序也就会不确定
2017-01-10 22:50:53.816 GCD-01[14340:1423863] 用户登录
2017-01-10 22:50:53.816 GCD-01[14340:1423979] 支付任务
2017-01-10 22:50:53.816 GCD-01[14340:1423977] 下载任务
对模拟项目升级
在之前的项目中,所以的点击添加任务都是在主线程中添加的,下面模拟一下在,子线程中添加上述的同步任务会出现什么情况:
- (void)gcdStrongSyncTask {
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create(myQueue, DISPATCH_QUEUE_CONCURRENT);
//这里讲之前的任务 放到task代码快中
void (^task)() = ^{
for (NSInteger i = 0; i < 10; i ++) {
dispatch_sync(queue, ^{
NSLog(@"%ld ------ %@", (long)i, [NSThread currentThread]);
});
}
//同步添加 用户登录 任务
dispatch_sync(queue, ^{
NSLog(@"用户登录 %@", [NSThread currentThread]);
});
//异步添加 支付任务 可以在子线程中执行
dispatch_async(queue, ^{
NSLog(@"支付任务 %@", [NSThread currentThread]);
});
//异步添加 下载任务 可以在子线程中执行
dispatch_async(queue, ^{
NSLog(@"下载任务 %@", [NSThread currentThread]);
});
};
//以异步任务的方式,将task在子线程中去执行,从而完成在子线程中去执行之前的任务
dispatch_async(queue, task);
NSLog(@" I come here %@", [NSThread currentThread]);
}
以下结果是我多次点击之后得到的,我选取其中有代表性的一段,可以发现两点:
- 将之前的任务放在block中,从新以异步任务方式添加到队列中,就会在子线程中执行
- "下载任务"会在"支付任务之前完成"
2017-01-10 23:05:00.053 GCD-01[14704:1458015] I come here <NSThread: 0x60000006e440>{number = 1, name = main}
2017-01-10 23:05:00.053 GCD-01[14704:1458400] 0 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.054 GCD-01[14704:1458400] 1 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.054 GCD-01[14704:1458400] 2 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.055 GCD-01[14704:1458400] 3 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.055 GCD-01[14704:1458400] 4 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.055 GCD-01[14704:1458400] 5 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.056 GCD-01[14704:1458400] 6 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.056 GCD-01[14704:1458400] 7 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.056 GCD-01[14704:1458400] 8 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.056 GCD-01[14704:1458400] 9 ------ <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.057 GCD-01[14704:1458400] 用户登录 <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.057 GCD-01[14704:1458400] 支付任务 <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.057 GCD-01[14704:1458089] 下载任务 <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.573 GCD-01[14704:1458015] I come here <NSThread: 0x60000006e440>{number = 1, name = main}
2017-01-10 23:05:00.573 GCD-01[14704:1458089] 0 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.574 GCD-01[14704:1458089] 1 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.574 GCD-01[14704:1458089] 2 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.574 GCD-01[14704:1458089] 3 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.575 GCD-01[14704:1458089] 4 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.575 GCD-01[14704:1458089] 5 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.575 GCD-01[14704:1458089] 6 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.575 GCD-01[14704:1458089] 7 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.576 GCD-01[14704:1458089] 8 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.576 GCD-01[14704:1458089] 9 ------ <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.576 GCD-01[14704:1458089] 用户登录 <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
2017-01-10 23:05:00.577 GCD-01[14704:1458400] 下载任务 <NSThread: 0x608000070600>{number = 6, name = (null)}
2017-01-10 23:05:00.577 GCD-01[14704:1458089] 支付任务 <NSThread: 0x61800006dbc0>{number = 5, name = (null)}
总结
对于GCD的基本使用,注意以下三点:
- 串行队列每次只能执行一个任务,不管是同步还是异步,因为队列本身只会等当前任务完成后才能去取出下一个任务,入口限制;
- 并行队列同步执行时:即使能从队列中获取多个任务,也只能等待,因为同步执行,不会创建子线程,所有任务都只能在当前线程中完成,而当前线程,只能等当前任务执行完,才能去执行下一个任务,出口限制;
- 并行队列异步执行:并行队列可以获取多个任务,异步执行可以获取多个线程,所以会出现并发执行,没有限制。
网友评论
非要挑剔的话,这里其实有一点不是太严谨。
即使所有任务都只在同一条线程上执行,但。。。下一个任务不一定非要等待上一个任务执行完成后才会执行。。。这个是单线程异步,类似node.js。
当然,并不是说你这里错了,只是不严谨,结合上下文大家都知道想表达的意思。
后台的话。。。。我暂时只知道node.js是这种模式。PHP之类的是没有event loop的,所以无法实现单线程异步操作。
单线程异步:我自己也是看了你的回复才找了资料,看了看,之前都不了解这个概念,
不过这中方式,对于移动端来说,应该很少涉及,在后台的并发操作处理上,应用场景更多一些,可以减少性能开支