深入浅出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 —— 所学即所用_第1张图片
队列、任务、线程池

如上图,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 *)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 ------ {number = 1, name = main}
2017-01-10 21:54:58.609 GCD-01[13124:1295897] 1 ------ {number = 1, name = main}
2017-01-10 21:54:58.609 GCD-01[13124:1295897] 2 ------ {number = 1, name = main}
2017-01-10 21:54:58.610 GCD-01[13124:1295897] 3 ------ {number = 1, name = main}
2017-01-10 21:54:58.610 GCD-01[13124:1295897] 4 ------ {number = 1, name = main}
2017-01-10 21:54:58.610 GCD-01[13124:1295897] 5 ------ {number = 1, name = main}
2017-01-10 21:54:58.610 GCD-01[13124:1295897] 6 ------ {number = 1, name = main}
2017-01-10 21:54:58.611 GCD-01[13124:1295897] 7 ------ {number = 1, name = main}
2017-01-10 21:54:58.611 GCD-01[13124:1295897] 8 ------ {number = 1, name = main}
2017-01-10 21:54:58.611 GCD-01[13124:1295897] 9 ------ {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 {number = 1, name = main}
2017-01-10 22:06:01.703 GCD-01[13385:1322734] 0 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.703 GCD-01[13385:1322734] 1 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.703 GCD-01[13385:1322734] 2 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.703 GCD-01[13385:1322734] 3 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.704 GCD-01[13385:1322734] 4 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.704 GCD-01[13385:1322734] 5 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.704 GCD-01[13385:1322734] 6 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.705 GCD-01[13385:1322734] 7 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.705 GCD-01[13385:1322734] 8 ------ {number = 3, name = (null)}
2017-01-10 22:06:01.705 GCD-01[13385:1322734] 9 ------ {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 ------ {number = 1, name = main}
2017-01-10 22:12:34.551 GCD-01[13537:1337073] 1 ------ {number = 1, name = main}
2017-01-10 22:12:34.551 GCD-01[13537:1337073] 2 ------ {number = 1, name = main}
2017-01-10 22:12:34.552 GCD-01[13537:1337073] 3 ------ {number = 1, name = main}
2017-01-10 22:12:34.552 GCD-01[13537:1337073] 4 ------ {number = 1, name = main}
2017-01-10 22:12:34.552 GCD-01[13537:1337073] 5 ------ {number = 1, name = main}
2017-01-10 22:12:34.552 GCD-01[13537:1337073] 6 ------ {number = 1, name = main}
2017-01-10 22:12:34.553 GCD-01[13537:1337073] 7 ------ {number = 1, name = main}
2017-01-10 22:12:34.553 GCD-01[13537:1337073] 8 ------ {number = 1, name = main}
2017-01-10 22:12:34.553 GCD-01[13537:1337073] 9 ------ {number = 1, name = main}
2017-01-10 22:12:34.553 GCD-01[13537:1337073] I am here {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 {number = 1, name = main}
2017-01-10 22:18:15.768 GCD-01[13664:1350805] 0 ------ {number = 3, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351252] 1 ------ {number = 4, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351253] 2 ------ {number = 5, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351254] 3 ------ {number = 6, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351255] 4 ------ {number = 7, name = (null)}
2017-01-10 22:18:15.768 GCD-01[13664:1351256] 5 ------ {number = 8, name = (null)}
2017-01-10 22:18:15.769 GCD-01[13664:1351257] 6 ------ {number = 9, name = (null)}
2017-01-10 22:18:15.769 GCD-01[13664:1351258] 7 ------ {number = 10, name = (null)}
2017-01-10 22:18:15.769 GCD-01[13664:1350805] 8 ------ {number = 3, name = (null)}
2017-01-10 22:18:15.769 GCD-01[13664:1351252] 9 ------ {number = 4, name = (null)}


2017-01-10 22:18:24.114 GCD-01[13664:1350605] I am here {number = 1, name = main}
2017-01-10 22:18:24.115 GCD-01[13664:1351637] 1 ------ {number = 12, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351259] 0 ------ {number = 11, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351638] 2 ------ {number = 13, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351639] 3 ------ {number = 14, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351641] 4 ------ {number = 15, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351643] 5 ------ {number = 16, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351640] 7 ------ {number = 18, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351644] 6 ------ {number = 17, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351637] 8 ------ {number = 12, name = (null)}
2017-01-10 22:18:24.115 GCD-01[13664:1351647] 9 ------ {number = 19, name = (null)}


2017-01-10 22:18:26.446 GCD-01[13664:1350605] I am here {number = 1, name = main}
2017-01-10 22:18:26.446 GCD-01[13664:1351647] 0 ------ {number = 19, name = (null)}
2017-01-10 22:18:26.446 GCD-01[13664:1351637] 1 ------ {number = 12, name = (null)}
2017-01-10 22:18:26.446 GCD-01[13664:1351644] 2 ------ {number = 17, name = (null)}
2017-01-10 22:18:26.446 GCD-01[13664:1351640] 3 ------ {number = 18, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351643] 4 ------ {number = 16, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351641] 5 ------ {number = 15, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351639] 6 ------ {number = 14, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351638] 7 ------ {number = 13, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351259] 8 ------ {number = 11, name = (null)}
2017-01-10 22:18:26.447 GCD-01[13664:1351646] 9 ------ {number = 20, name = (null)}



2017-01-10 22:18:26.598 GCD-01[13664:1351646] 0 ------ {number = 20, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1350605] I am here {number = 1, name = main}
2017-01-10 22:18:26.598 GCD-01[13664:1351259] 1 ------ {number = 11, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351638] 2 ------ {number = 13, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351639] 3 ------ {number = 14, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351641] 4 ------ {number = 15, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351643] 5 ------ {number = 16, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351640] 6 ------ {number = 18, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351644] 7 ------ {number = 17, name = (null)}
2017-01-10 22:18:26.598 GCD-01[13664:1351637] 8 ------ {number = 12, name = (null)}
2017-01-10 22:18:26.599 GCD-01[13664:1351649] 9 ------ {number = 21, name = (null)}



2017-01-10 22:18:26.734 GCD-01[13664:1351637] 1 ------ {number = 12, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351649] 0 ------ {number = 21, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351644] 2 ------ {number = 17, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1350605] I am here {number = 1, name = main}
2017-01-10 22:18:26.734 GCD-01[13664:1351640] 3 ------ {number = 18, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351643] 4 ------ {number = 16, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351641] 5 ------ {number = 15, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351639] 6 ------ {number = 14, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351638] 7 ------ {number = 13, name = (null)}
2017-01-10 22:18:26.734 GCD-01[13664:1351259] 8 ------ {number = 11, name = (null)}
2017-01-10 22:18:26.735 GCD-01[13664:1351646] 9 ------ {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    {number = 1, name = main}
2017-01-10 23:05:00.053 GCD-01[14704:1458400] 0 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.054 GCD-01[14704:1458400] 1 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.054 GCD-01[14704:1458400] 2 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.055 GCD-01[14704:1458400] 3 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.055 GCD-01[14704:1458400] 4 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.055 GCD-01[14704:1458400] 5 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.056 GCD-01[14704:1458400] 6 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.056 GCD-01[14704:1458400] 7 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.056 GCD-01[14704:1458400] 8 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.056 GCD-01[14704:1458400] 9 ------ {number = 6, name = (null)}
2017-01-10 23:05:00.057 GCD-01[14704:1458400] 用户登录  {number = 6, name = (null)}
2017-01-10 23:05:00.057 GCD-01[14704:1458400] 支付任务   {number = 6, name = (null)}
2017-01-10 23:05:00.057 GCD-01[14704:1458089] 下载任务  {number = 5, name = (null)}




2017-01-10 23:05:00.573 GCD-01[14704:1458015]  I come here    {number = 1, name = main}
2017-01-10 23:05:00.573 GCD-01[14704:1458089] 0 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.574 GCD-01[14704:1458089] 1 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.574 GCD-01[14704:1458089] 2 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.574 GCD-01[14704:1458089] 3 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.575 GCD-01[14704:1458089] 4 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.575 GCD-01[14704:1458089] 5 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.575 GCD-01[14704:1458089] 6 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.575 GCD-01[14704:1458089] 7 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.576 GCD-01[14704:1458089] 8 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.576 GCD-01[14704:1458089] 9 ------ {number = 5, name = (null)}
2017-01-10 23:05:00.576 GCD-01[14704:1458089] 用户登录  {number = 5, name = (null)}
2017-01-10 23:05:00.577 GCD-01[14704:1458400] 下载任务  {number = 6, name = (null)}
2017-01-10 23:05:00.577 GCD-01[14704:1458089] 支付任务   {number = 5, name = (null)}

总结

对于GCD的基本使用,注意以下三点:

  • 串行队列每次只能执行一个任务,不管是同步还是异步,因为队列本身只会等当前任务完成后才能去取出下一个任务,入口限制;
  • 并行队列同步执行时:即使能从队列中获取多个任务,也只能等待,因为同步执行,不会创建子线程,所有任务都只能在当前线程中完成,而当前线程,只能等当前任务执行完,才能去执行下一个任务,出口限制;
  • 并行队列异步执行:并行队列可以获取多个任务,异步执行可以获取多个线程,所以会出现并发执行,没有限制。

你可能感兴趣的:(深入浅出GCD —— 所学即所用)