GCD的使用

最近在学习GCD,所以在网上找了些资料,这里只是对自己学习的总结

1.概念

GCD的好处
GCD可用于多核的并行运算
GCD会自动利用更多的CPU内核(比如双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

  1. 任务和队列的概念
    任务: 任务就是执行操作的意思,就是在线程中执行的代码,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.队列组

有的时候我们需要分别执行多个异步操作,等所有的异步操作都结束之后在回到主线程执行操作,这时候可以使用队列组

  1. 先把任务放在队列里,并和队列组dispatch_group 相关联
  2. 使用dispatch_group_notify函数进行回到主线程操作
    • queue里所有的任务执行完毕之后才会执行dispatch_group_notify里的代码块
- (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是没有顺序的

你可能感兴趣的:(GCD的使用)