美文网首页
GCD之实例分析

GCD之实例分析

作者: 余大可 | 来源:发表于2017-07-21 15:00 被阅读0次

    iOS开发中,多线程的解决方案有四种:pthreadNSThreadGCDNSOperation,对于我自己来说GCD用的最多,而这篇文章只负责通过几个GCD案例帮我们更好的理解线程队列,以及线程同步异步的关系,关于其他线程解决方案的原理和应用就不多赘述了。

    一、GCD的特点

    • GCD会自动利用更多的CPU内核。
    • GCD自动管理线程的生命周期(创建线程,调度任务,毁掉线程等)。
    • 程序员只需要告诉GCD想要如何执行什么任务,不需要编写任何线程管理代码。

    二、GCD的基本概念

    • 任务block:任务就是将要在线程中执行的代码,将这段代码用block封装好,然后将这个任务添加到指定的执行方式(同步执行和异步执行),等待CPU从队列中取出任务放到对应的线程中执行。

    • 同步sync:一个接着一个,前一个没有执行完,后面不能执行,不开线程。

    • 异步async:开启多个新线程,任务同一时间可以一起执行(异步是多线程的代名词)。

    • 队列:装载线程任务的队形结构。(系统以先进先出的方式调度队列中的任务执行)。在GCD中有两种队列:串行队列和并发队列。

    • 并发队列:线程可以同时一起进行执行。实际上是CPU在多条线程之间快速的切换。(并发功能只有在异步dispatch_async函数下才有效)

    • 串行队列:线程只能依次有序的执行。

    GCD总结:将任务(要在线程中执行的操作block)添加到队列(自己创建或使用全局并发队列),并且指定执行任务的方式(异步dispatch_async,同步dispatch_sync)

    三、API

    了解了基本概念,这里在介绍下本文用到几个GCD API:

    1. 系统标准提供的两个队列
    //全局队列,也是一个并发队列
        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //主队列,在主线程中运行,因为主线程直有一个,所以这是一个串行队列
        dispatch_get_main_queue();
    
    1. 我们还可以自己创建队列
    // 从DISPATCH_QUEUE_SERIAL看出,这是串行队列
        dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
        // 同理,这是一个并发队列
        dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    
    1. 最后就是同步和异步线程了
    //同步线程
        dispatch_sync(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
        //异步线程
        dispatch_async(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
    

    四、案例分析

    • 案例一

    NSLog(@"1");//任务1
    dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"2");//任务2
        });
    NSLog(@"3");//任务3
    

    分析:输出结果:1,然后程序崩溃。

    dispatch_sync表示是一个同步线程;
    dispatch_get_main_queue表示运行在主线程中的主队列;
    任务2是同步线程的任务。

    首先执行任务1,这是肯定没问题的,只是接下来,程序遇到了同步线程,那么它会进入等待,等待任务2执行完,然后执行任务3。但这是主队列,有任务来,当然会将任务加到队尾,然后遵循FIFO原则执行任务。那么,现在任务2就会被加到最后,任务3排在了任务2前面,问题来了:
    任务3要等任务2执行完才能执行,任务2由排在任务3后面,意味着任务2要在任务3执行完才能执行,所以他们进入了互相等待的局面。【既然这样,那干脆就卡在这里吧】这就是死锁。

    • 案例二

    NSLog(@"1"); // 任务1
    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            NSLog(@"2"); // 任务2
        });
    NSLog(@"3"); // 任务3
    

    分析:输出结果:1,2,3。
    首先执行任务1,然后遇到一个同步线程,线程会进入等待。等待任务2执行完成后才能执行任务3。从dispatch_get_global_queue可以看出,任务2被加入到了全局并发队列中,和主队列并不冲突,所以在并行队列执行完任务2之后,返回到主队列,执行任务3。

    • 案例三

    dispatch_queue_t queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); // 任务1
    dispatch_async(queue, ^{
          NSLog(@"2"); // 任务2
          dispatch_sync(queue, ^{
              NSLog(@"3"); // 任务3
          });
          NSLog(@"4"); // 任务4
      });
    NSLog(@"5"); // 任务5
    

    分析:控制台输出1,5,2(5/2顺序不确定),然后崩溃。
    queue是自己创建的串行队列。
    首先执行任务1,遇到异步线程,将【任务2,同步线程,任务4】加入到串行队列 queue中。因为是异步线程,所以主线程中的任务5不用等异步线程中的任务完成就可以执行(但是5和2谁先执行也不一定)。任务2执行完毕后,遇到同步线程,任务3加入到队列queue中,以为任务4比任务3更早加入到串行队列queue中,所以任务3要等任务4完成后才能执行,但是任务3所在的同步线程又会阻塞,所以任务4要等任务3完成后在执行,这就陷入了无限的等待中,造成死锁。

    • 案例四

    NSLog(@"1"); // 任务1
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"2"); // 任务2
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"3"); // 任务3
            });
            NSLog(@"4"); // 任务4
        });
    NSLog(@"5"); // 任务5
    

    分析:控制台输出结果1,5,2,3,4(5/2顺序不一定)。
    首先将【任务1,异步线程,任务5】加入到主队列中,异步线程中的任务是:【任务2,同步线程,任务4】。
    先执行任务1,然后将异步线程的人物加到global_queue中,因为是异步线程,所以任务5不用等待,直接可以执行,但2和5的顺序不一定。
    然后再看异步线程中的任务执行顺序,任务2执行完成之后,遇到同步线程,但是同步线程中的任务是加到main queue中的,所以在主队列中完成任务3,再回到全局队列完成任务4。

    • 案例五

        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"1"); // 任务1
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"2"); // 任务2
            });
            NSLog(@"3"); // 任务3
        });
        NSLog(@"4"); // 任务4
        while (1) {
        }
        NSLog(@"5"); // 任务5
    

    分析:控制台输出:4,1。(1/4顺序不一定)
    加入到主队列中的任务【异步线程,任务4,死循环,任务5】。
    加入到异步线程中的任务【任务1,同步线程,任务3】。
    任务4完成之后,程序进入死循环,主队列阻塞。但是加入到全局队列中的异步线程不受影响,继续执行任务1后面的同步线程。
    由于同步线程的任务2加入到主队列,而主队列阻塞,任务2无法执行,而任务3要等同步线程中的任务2完成才能执行,所以任务3也无法执行。
    而由于死循环任务5也不会执行。

    相关文章

      网友评论

          本文标题:GCD之实例分析

          本文链接:https://www.haomeiwen.com/subject/pqnskxtx.html