最近在学习GCD,所以在网上找了些资料,这里只是对自己学习的总结
1.概念
GCD的好处
GCD可用于多核的并行运算
GCD会自动利用更多的CPU内核(比如双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
- 任务和队列的概念
任务: 任务就是执行操作的意思,就是在线程中执行的代码,GCD是放在block中
执行任务有两种方式 :
1.异步执行
2.同步执行
队列:队列是一种特殊的线性表,按照FIFO(先进先出)的原则存放任务,即新任务总是被插在队列的末尾,读取任务的时候总是从队列的头部开始读取, 每读取一个任务,就从队列中释放一个任务,
GCD有两种队列 :
1.串行队列
2.并发队列
2.使用
1.创建
GCD的使用步骤很简单
- 创建一个队列(串行队列/并发队列)
- 将任务添加到队列中
2.队列的创建方法
可以使用dispatch_queue_create
函数来创建,一共有两个参数, 第一个参数是队列的唯一标识符,第二个参数表明是串行队列还是并发队列,串行队列是DISPATCH_QUEUE_SERIAL
,并发队列是DISPATCH_QUEUE_CONCURRENT
1.创建串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("唯一标识符", DISPATCH_QUEUE_SERIAL);
2.创建并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
3.任务的创建方法
1.异步执行任务
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);//这里放置任务代码
});
2.同步执行任务
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);//这里放置任务代码
});
3.组合使用
使用GCD只有两步,但我们有两种队列方式,两种任务执行方式,这样的话我们就有了四种组合方式
并发队列 + 同步执行
并发队列 + 异步执行
串行队列 + 同步执行
串行队列 + 异步执行
1. 并发队列 + 同步执行
- (void)concurrentSync {
//1.创建并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"concurrentSync begin ------------- %@", [NSThread currentThread]);
dispatch_sync(concurrentQueue, ^{
NSLog(@"任务1 -- %@", [NSThread currentThread]);
});
dispatch_sync(concurrentQueue, ^{
NSLog(@"任务2 -- %@", [NSThread currentThread]);
});
dispatch_sync(concurrentQueue, ^{
NSLog(@"任务3 -- %@", [NSThread currentThread]);
});
dispatch_sync(concurrentQueue, ^{
NSLog(@"任务4 -- %@", [NSThread currentThread]);
});
NSLog(@"concurrentSync end ------------- %@", [NSThread currentThread]);
}
打印信息为
concurrentSync begin ------------- {number = 1, name = main}
任务1 -- {number = 1, name = main}
任务2 -- {number = 1, name = main}
任务3 -- {number = 1, name = main}
任务4 -- {number = 1, name = main}
concurrentSync end ------------- {number = 1, name = main}
小结:
并发队列 + 同步执行
并没有开启新的线程,是在当前线程(主线程)执行任务,由于只有一个线程,所以任务只能一个一个的执行所有的任务都是在concurrentSync begin 和concurrentSync end之间打印,说明任务添加到队列中之后就马上执行了
2.并发队列 + 异步执行
- (void)concurrentAsync {
//创建并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"concurrentAsync begin ------- %@", [NSThread currentThread]);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务1.%d -- %@",i, [NSThread currentThread]);
}
NSLog(@"任务1 -- %@", [NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务2.%d -- %@",i, [NSThread currentThread]);
}
NSLog(@"任务2 -- %@", [NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务3.%d -- %@",i, [NSThread currentThread]);
}
NSLog(@"任务3 -- %@", [NSThread currentThread]);
});
NSLog(@"concurrentAsync end ------- %@", [NSThread currentThread]);
}
打印信息为
concurrentAsync begin ------- {number = 1, name = main}
concurrentAsync end ------- {number = 1, name = main}
任务1.0 -- {number = 3, name = (null)}
任务3.0 -- {number = 5, name = (null)}
任务2.0 -- {number = 4, name = (null)}
任务1.1 -- {number = 3, name = (null)}
任务3.1 -- {number = 5, name = (null)}
任务2.1 -- {number = 4, name = (null)}
任务1 -- {number = 3, name = (null)}
任务3 -- {number = 5, name = (null)}
任务2 -- {number = 4, name = (null)}
小结:
- 在
并发队列+异步执行
,又开辟了三条子线程,并且任务是交替执行的,即三个线程里的任务执行顺序是不一定的- 所有的任务都是在打印concurrentAsync begin 和concurrentAsync end之后才开始执行,说明任务不是马上执行,而是将所有的任务都添加到队列之后才开始异步执行
3. 串行队列+同步执行
- (void)serialSync {
dispatch_queue_t serialQueue = dispatch_queue_create("名字", DISPATCH_QUEUE_SERIAL);
NSLog(@"serialSync begin ------------ %@", [NSThread currentThread]);
dispatch_sync(serialQueue, ^{
NSLog(@"serialSync任务1 -- %@", [NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"serialSync任务2 -- %@", [NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"serialSync任务3 -- %@", [NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"serialSync任务4 -- %@", [NSThread currentThread]);
});
NSLog(@"serialSync end ------------- %@", [NSThread currentThread])
}
打印信息为
serialSync begin ------------- {number = 1, name = main}
serialSync任务1 -- {number = 1, name = main}
serialSync任务2 -- {number = 1, name = main}
serialSync任务3 -- {number = 1, name = main}
serialSync任务4 -- {number = 1, name = main}
serialSync end ------------- {number = 1, name = main}
小结:
- 在
串行队列+同步执行
中,并没有开启新的线程,是在当前线程(主线程)执行任务,并且任务是顺序执行的- 所有的任务都是在serialSync begin 和serialSync end 之间打印的 说明任务添加到队列中之后马上就执行了
4.串行队列+异步执行
- (void)serialAsync {
dispatch_queue_t serialQueue = dispatch_queue_create("名字", DISPATCH_QUEUE_SERIAL);
NSLog(@"begin ------------- %@", [NSThread currentThread]);
dispatch_async(serialQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务1.%d -- %@", i,[NSThread currentThread]);
}
NSLog(@"任务1 -- %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务2.%d -- %@", i,[NSThread currentThread]);
}
NSLog(@"任务2 -- %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务3.%d -- %@", i,[NSThread currentThread]);
}
NSLog(@"任务3 -- %@", [NSThread currentThread]);
});
NSLog(@"end ------------- %@", [NSThread currentThread]);
}
打印信息为
begin ------------- {number = 1, name = main}
end ------------- {number = 1, name = main}
任务1.0 -- {number = 3, name = (null)}
任务1.1 -- {number = 3, name = (null)}
任务1 -- {number = 3, name = (null)}
任务2.0 -- {number = 3, name = (null)}
任务2.1 -- {number = 3, name = (null)}
任务2 -- {number = 3, name = (null)}
任务3.0 -- {number = 3, name = (null)}
任务3.1 -- {number = 3, name = (null)}
任务3 -- {number = 3, name = (null)}
小结:
串行队列+异步执行
会开启新的线程,但因为是串行队列,所以只会开启一个新线程,由于只有一个新的线程,所以任务是顺序执行的,执行完一个任务再执行下一个任务- 所有的任务都是在begin -------------和end -------------之后打印,说明任务不是马上执行的,而是将所有的任务都添加到队列中之后才开始顺序执行
4.主队列
- 主队列是和主线程相关联的一种特殊的串行队列,所有放在主队列中的任务都会在主线程中执行
- 可使用
dispatch_get_main_queue()
函数 获取主队列
1.主队列 + 同步执行
主队列+同步执行
的形式不能在主线程中被调用 必须在其他线程调用 否则会崩溃
- (void)mainQueueSync {
//1.获取主队列的方式
dispatch_queue_t mainQueue = dispatch_get_main_queue();
NSLog(@"begin ------------- %@", [NSThread currentThread])
dispatch_sync(mainQueue, ^{
NSLog(@"主队列中同步执行任务1 -- %@", [NSThread currentThread]);
});
dispatch_sync(mainQueue, ^{
NSLog(@"主队列中同步执行任务2 -- %@", [NSThread currentThread]);
});
dispatch_sync(mainQueue, ^{
NSLog(@"主队列中同步执行任务3 -- %@", [NSThread currentThread]);
});
NSLog(@"end ------------- %@", [NSThread currentThread]);
}
打印信息为
begin ------------- {number = 3, name = (null)}
主队列中同步执行任务1 -- {number = 1, name = main}
主队列中同步执行任务2 -- {number = 1, name = main}
主队列中同步执行任务3 -- {number = 1, name = main}
end ------------- {number = 3, name = (null)}
小结:
在其他线程里调用
主队列+同步执行
可以看到,所有的任务都是在主线程中执行,并且由于主队列是串行队列,所以任务是顺序执行任务的打印是在begin和end之间打印,说明任务是立即执行的
在主线程调用会崩溃,因为我们把任务是放在主队列同步执行,也就是主线程的队列,而同步执行有个特点,就是对于任务是会立马执行,当我们把任务1放到主队列中之后,任务1会马上执行,但是主线程现在正在处理
- (void)mainQueueSync
方法,所以任务1需要等到- (void)mainQueueSync
结束之后才会执行,但是- (void)mainQueueSync
方法执行完毕又需要执行到下面任务2 任务3, 但是任务1 没有执行完毕又不能往下执行,造成了死循环
2.主队列+异步执行
- (void)mainQueueAsync {
//1.获取主队列的方式
dispatch_queue_t mainQueue = dispatch_get_main_queue();
NSLog(@"begin ------------- %@", [NSThread currentThread]);
dispatch_async(mainQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务1.%d ------ %@", i, [NSThread currentThread]);
}
NSLog(@"任务1 -- %@", [NSThread currentThread]);
});
dispatch_async(mainQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务2.%d ------ %@", i, [NSThread currentThread]);
}
NSLog(@"任务2 -- %@", [NSThread currentThread]);
});
dispatch_async(mainQueue, ^{
for (int i = 0; i < 2; i++) {
NSLog(@"任务3.%d ------ %@", i, [NSThread currentThread]);
}
NSLog(@"任务3 -- %@", [NSThread currentThread]);
});
NSLog(@"end ------------- %@", [NSThread currentThread]);
}
打印信息为:
begin ------------- {number = 1, name = main}
end ------------- {number = 1, name = main}
任务1.0 ------ {number = 1, name = main}
任务1.1 ------ {number = 1, name = main}
任务1 -- {number = 1, name = main}
任务2.0 ------ {number = 1, name = main}
任务2.1 ------ {number = 1, name = main}
任务2 -- {number = 1, name = main}
任务3.0 ------ {number = 1, name = main}
任务3.1 ------ {number = 1, name = main}
任务3 -- {number = 1, name = main}
小结:
主队列+异步执行
虽然是异步执行,但不会开启新的线程,所有的任务都是在主线程中执行,并且任务是顺序执行的,在一个任务完成之后在执行下一个任务打印的信息是在begin-----和end--------之后,说明任务不是立马执行的,是在所有的任务都加入到队列之后才开始执行
从上面可以得出下面的表格内容
是否开启新线程 | 任务执行顺序 | 任务执行时间 | |
---|---|---|---|
并发队列+ 同步执行 | 在当前线程执行任务 | 顺序执行(执行完一个任务再执行下一个任务) | 马上执行 |
并发队列 + 异步执行 | 开启新线程执行任务 | 交替执行 | 所有任务都添加到队列之后才开始执行 |
串行队列+ 同步执行 | 在当前线程执行任务 | 顺序执行 | 马上执行 |
串行队列 + 异步执行 | 开启新线程执行(只开启一个新线程) | 顺序执行 | 所有任务添加到队列之后才开始执行 |
主队列+同步执行(必须在其他线程调用,不能在主线程调用) | 在主线程执行 | 顺序执行 | 马上执行 |
主队列+异步执行 | 在主线程执行 | 顺序执行 | 所有任务添加之后再执行 |
- 是否开启新的线程取决于任务的执行方式
- 异步执行会开启新的线程
- 同步执行不会开启新的线程
- 只有并发队列+异步执行时任务的执行顺序是交替执行的,其他组合任务的执行都是顺序 的,即只要是串行队列任务就是有顺序的执行,只要是同步执行任务也是顺序执行
- 任务执行时间取决于任务执行方式
- 异步执行:所有任务都添加到队列之后才开始执行
- 同步执行:任务添加到队列之后马上执行
- 串行队列最多只会开启一条新的线程
5.线程间的通讯
iOS开发过程中,我们一般在主线程里边进行UI刷新,例如:点击、滚动、拖拽等事件。我们通常把一些耗时的操作放在其他线程,比如说图片下载、文件上传等耗时操作。而当我们有时候在其他线程完成了耗时操作时,需要回到主线程,那么就用到了线程之间的通讯
- (void)threadCommunication {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < 2; ++i) {
NSLog(@"1.%d------%@",i,[NSThread currentThread]);
}
// 回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"2-------%@",[NSThread currentThread]);
});
});
}
打印信息为
1.0------{number = 3, name = (null)}
1.1------{number = 3, name = (null)}
2-------{number = 1, name = main}
小结:
- 可以看到在其他线程中先执行操作,执行完了之后回到主线程执行主线程的相应操作
6.其他用法
1.GCD栅栏
有的时候当我们执行多组操作的时候,会需要等到第一组操作完成之后再执行第二部分的操作,这时候就需要一个类似于栅栏的方法来把这几组操作分割开来,这里的操作组可以含有一个或者多个任务
- 使用
dispatch_barrier_async
函数来形成栅栏
- (void)barrierAsync {
dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1---------- %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2---------- %@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"barrier ---------- %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3---------- %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"4---------- %@",[NSThread currentThread]);
});
}
打印信息为
2---------- {number = 3, name = (null)}
1---------- {number = 4, name = (null)}
barrier ---------- {number = 4, name = (null)}
3---------- {number = 4, name = (null)}
4---------- {number = 3, name = (null)}
小结:
- 可以看出 总是在执行完栅栏前面的操作之后才开始执行栅栏的操作,然后在执行栅栏之后的操作
2.GCD延时
使用dispatch_after
函数
- (void)dispatchAfter {
NSLog(@"bengin ---------- %@",[NSThread currentThread]);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"1 ---------- %@",[NSThread currentThread]);
});
NSLog(@"end ---------- %@",[NSThread currentThread]);
}
打印信息为
2017-03-03 13:16:37.316 GCDDemo[1037:77501] bengin ---------- {number = 1, name = main}
2017-03-03 13:16:37.316 GCDDemo[1037:77501] end ---------- {number = 1, name = main}
2017-03-03 13:16:42.316 GCDDemo[1037:77501] 1 ---------- {number = 1, name = main}
小结:
- 从前面的打印信息来看,
dispatch_after
的代码是在晚了5s之后才打印的
3.队列组
有的时候我们需要分别执行多个异步操作,等所有的异步操作都结束之后在回到主线程执行操作,这时候可以使用队列组
- 先把任务放在队列里,并和队列组
dispatch_group
相关联 - 使用
dispatch_group_notify
函数进行回到主线程操作- queue里所有的任务执行完毕之后才会执行
dispatch_group_notify
里的代码块
- queue里所有的任务执行完毕之后才会执行
- (void)dispatchGroup {
// 1.创建队列组
dispatch_group_t group = dispatch_group_create();
// 2.获得全局队列 GCD已经提供了全局的并发队列供整个应用使用,所以不用手动创建
// 第一个参数是设置队列的优先级,这里设置为default,第二个参数是苹果的保留字段,为了将来使用,所以现在写0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@" begin ----------- %@", [NSThread currentThread]);
dispatch_group_async(group, queue, ^{
NSLog(@" 1 ----------- %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@" 2 ----------- %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@" 3 ----------- %@", [NSThread currentThread])
});
dispatch_group_async(group, queue, ^{
NSLog(@" 4 ----------- %@", [NSThread currentThread]);
});
dispatch_group_notify(group, queue, ^{
NSLog(@" 最后的任务 ----------- %@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{//回到主线程
NSLog(@"回到主线程进行操作 --- %@", [NSThread currentThread])
});
});
NSLog(@" end ----------- %@", [NSThread currentThread]);
}
打印信息为
begin ----------- {number = 1, name = main}
end ----------- {number = 1, name = main}
1 ----------- {number = 3, name = (null)}
2 ----------- {number = 4, name = (null)}
4 ----------- {number = 6, name = (null)}
3 ----------- {number = 5, name = (null)}
最后的任务 ----------- {number = 5, name = (null)}
回到主线程进行操作 --- {number = 1, name = main}
小结:
- 可以看到前面的四个任务的执行时没有顺序的, 但总是在四个任务执行之后才会执行dispatch_group_notify的代码
dispatch_group_enter( )和dispatch_group_leave( )
dispatch_group_enter( )的官方文档为
Calling this function indicates another block has joined the group through a means other than dispatch_group_async(). Calls to this function must be balanced with dispatch_group_leave().
个人翻译是
通过一个不同于dispatch_group_async()
的方法将一个代码块加入到group中,必须和dispatch_group_leave()
方法一块使用
- (void)groupEnterAndLeave {
// 1.创建队列组
dispatch_group_t group = dispatch_group_create();
// 2.获得全局队列
// 第一个参数是设置队列的优先级,这里设置为default,第二个参数暂时没用到,可以先写作0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@" begin ----------- %@", [NSThread currentThread]);
//进入组
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"任务 1 ----------- %@", [NSThread currentThread]);
//离开组
dispatch_group_leave(group);
});
//进入组
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"任务 2 ----------- %@", [NSThread currentThread]);
//离开组
dispatch_group_leave(group);
});
//进入组
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"任务 3 ----------- %@", [NSThread currentThread]);
//离开组
dispatch_group_leave(group);
});
/* 因为队列queue里所有的任务执行完毕之后才会执行dispatch_group_notify里的代码块
所以即使dispatch_group_notify放在任务 4 前面,也是先执行任务 4的代码
在执行这里的代码 不过为了好看,还是把dispatch_group_notify放在任务 4 后面
dispatch_group_notify(group, queue, ^{
NSLog(@" 最后的任务 ----------- %@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{//回到主线程
NSLog(@"回到主线程进行操作 --- %@", [NSThread currentThread]);
});
});
*/
//进入组
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"任务 4 ----------- %@", [NSThread currentThread]);
//离开组
dispatch_group_leave(group);
});
dispatch_group_notify(group, queue, ^{
NSLog(@" 最后的任务 ----------- %@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{//回到主线程
NSLog(@"回到主线程进行操作 --- %@", [NSThread currentThread]);
});
});
NSLog(@" end ----------- %@", [NSThread currentThread]);
}
打印信息为
begin ----------- {number = 1, name = main}
end ----------- {number = 1, name = main}
任务 1 ----------- {number = 3, name = (null)}
任务 2 ----------- {number = 4, name = (null)}
任务 3 ----------- {number = 5, name = (null)}
任务 4 ----------- {number = 6, name = (null)}
最后的任务 ----------- {number = 6, name = (null)}
回到主线程进行操作 --- {number = 1, name = main}
小结:
- 可以看到,通过enter和leave的方式,我们可以使异步函数有顺序的执行,这个特点使得它很适合处理异步任务的同步事件,比如我们异步请求多组数据(有多个接口),请求的数据需要有序的放入到数组中(dataArray),这个时候就可以使用该方式
4.GCD快速迭代方法
通常我们会用for循环遍历,但是GCD提供了一种快速迭代的方法dispatch_apply,使我们可以同时遍历
- (void)dispatchApply {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 5; i++) {
NSLog(@" for循环 %d------%@",i, [NSThread currentThread]);
}
dispatch_apply(5, queue, ^(size_t index) {
NSLog(@"Apply -- %zd------%@",index, [NSThread currentThread]);
});
}
打印信息为
2017-03-03 13:25:03.836 GCDDemo[1113:82201] Apply -- 1------{number = 3, name = (null)}
2017-03-03 13:25:03.836 GCDDemo[1113:82148] Apply -- 0------{number = 1, name = main}
2017-03-03 13:25:03.836 GCDDemo[1113:82209] Apply -- 2------{number = 4, name = (null)}
2017-03-03 13:25:03.836 GCDDemo[1113:82200] Apply -- 3------{number = 5, name = (null)}
2017-03-03 13:25:03.836 GCDDemo[1113:82148] Apply -- 5------{number = 1, name = main}
2017-03-03 13:25:03.836 GCDDemo[1113:82201] Apply -- 4------{number = 3, name = (null)}
2017-03-03 13:25:03.836 GCDDemo[1113:82148] for循环 0------{number = 1, name = main}
2017-03-03 13:25:03.836 GCDDemo[1113:82148] for循环 1------{number = 1, name = main}
2017-03-03 13:25:03.836 GCDDemo[1113:82148] for循环 2------{number = 1, name = main}
2017-03-03 13:25:03.836 GCDDemo[1113:82148] for循环 3------{number = 1, name = main}
2017-03-03 13:25:03.836 GCDDemo[1113:82148] for循环 4------{number = 1, name = main}
2017-03-03 13:25:03.837 GCDDemo[1113:82148] for循环 5------{number = 1, name = main}
小结:
- 从输出结果中前边的时间中可以看出,apply几乎是同时遍历的,for循环的话要比apply稍慢一些,这里不太明显, 但是如果循环次数再大一些的话会更明显;
- for循环是在当前线程顺序的执行,而apply会开启新的线程同时执行,所以for循环是有顺序的,apply是没有顺序的