深入浅出GCD —— 所学即所用

CGD简介

什么是GCD

  • GCD的全称是Grand Central Dispatch,可以把它翻译为"牛逼的中枢调度器"。😉
  • 纯C语言,提供了很多强大的函数

GCD的优势

  • GCD是苹果公司为解决多核的并行运算而提出的解决方案
  • CGD会自动利用更多的CPU内容(如双核、四核...)
  • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
  • 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

GCD中的概念和使用步骤

2个核心概念

任务:

执行的什么操作,用block代码块的形式创建

队列:

是用来陈放任务的载体,负责调度任务;队列有两种类型:

  • 串行队列:一个接一个的调度任务 (DISPATCH_QUEUE_SERIALdispatch_get_main_queue())
  • 并行队列:可以同时调度多个任务 (DISPATCH_QUEUE_CONCURRENTdispatch_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的基本使用,注意以下三点:

  • 串行队列每次只能执行一个任务,不管是同步还是异步,因为队列本身只会等当前任务完成后才能去取出下一个任务,入口限制;
  • 并行队列同步执行时:即使能从队列中获取多个任务,也只能等待,因为同步执行,不会创建子线程,所有任务都只能在当前线程中完成,而当前线程,只能等当前任务执行完,才能去执行下一个任务,出口限制;
  • 并行队列异步执行:并行队列可以获取多个任务,异步执行可以获取多个线程,所以会出现并发执行,没有限制。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容

  • 从哪说起呢? 单纯讲多线程编程真的不知道从哪下嘴。。 不如我直接引用一个最简单的问题,以这个作为切入点好了 在ma...
    Mr_Baymax阅读 2,719评论 1 17
  • 1. GCD简介 什么是GCD呢?我们先来看看百度百科的解释简单了解下概念 引自百度百科:Grand Centra...
    千寻_544f阅读 354评论 0 0
  • 什么是GCD 全称是GrandCentral Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多...
    JonesCxy阅读 284评论 0 1
  • 目录(GCD): 关键词 混淆点 场景应用 总结 1. 关键词 线程概念: 独立执行的代码段,一个线程同时间只能执...
    Ryan___阅读 1,247评论 0 3
  • 《C陷阱与缺陷》 Andrew Koenig 读书笔记 1.1 =和== 编写时建议:将变量放到==的后方,编译器...
    rfish阅读 735评论 2 9