美文网首页
iOS 常见面试题 --GCD

iOS 常见面试题 --GCD

作者: 奋斗的小马达 | 来源:发表于2021-02-20 10:15 被阅读0次

    一、简介

    Grand Central Dispatch(GCD) 是 Apple 开发的一个多核编程的较新的解决方法。
    它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。
    它是一个在线程池模式的基础上执行的并发任务。
    在 Mac OS X 10.6 雪豹中首次推出,也可在 iOS 4 及以上版本使用。
    

    为什么会使用GCD 他有什么好处

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

    二、核心概念--- 任务 和 队列

    任务: 同步、 异步

    1、区别

    同步和异步主要影响:能不能开启新的线程
    同步:在当前线程中执行任务,不具备开启新线程的能力
    异步:在新的线程中执行任务,具备开启新线程的能力
    

    2、常用函数

    用同步的方式执行任务
    dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
    用异步的方式执行任务
    dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
    
    注解
    queue:队列
    block:任务
    

    队列:并发队列、串行队列

    1、区别

    并发队列(Concurrent Dispatch Queue)
    可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
    并发功能只有在异步(dispatch_async)函数下才有效
    
    串行队列(Serial Dispatch Queue)
    让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
    

    三、各种队列的执行效果 如图所示:

    各种队列执行组合图.png

    主队列:线程默认的一个队列

    四、关于GCD的一些死锁

    核心概念:

    1、使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)
    
    2、队列是一种特殊的线性表,采用 FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾
    

    下面将结合几个例子来讲解GCD线程死锁(方法调用都是在主线程)

    例一:问题:以下代码是在主线程执行的,会不会产生死锁?

    - (void)question1{
    
        NSLog(@"执行任务1");
        
        dispatch_queue_t queue = dispatch_get_main_queue();
        dispatch_sync(queue, ^{
            NSLog(@"执行任务2");
        });
        
        NSLog(@"执行任务3");
        
    }
    
    分析:“任务1” 、 “任务2” 、“任务3” 都在主线程的主队列执行
    “任务1”首先执行   
    “任务2”  被添加到主队列  所以“任务2”会被添加到 “任务3”的后面  
    但是“任务2”又要求同步执行 所以在执行完 “任务1” 后要求立即执行“任务2”  
    但是“任务2” 又要等待“任务3” 执行完毕之后才能执行 这样就产生了死锁
    
    答案:会产生死锁 “任务2” 和“任务3” 相互等待
    

    例二:问题:以下代码是在主线程执行的,会不会产生死锁?

    - (void)question2{
    
        NSLog(@"执行任务1");
      
        dispatch_queue_t queue = dispatch_get_main_queue();
        dispatch_async(queue, ^{
            NSLog(@"执行任务2");
        });
        
        NSLog(@"执行任务3");
    }
    
    分析:“任务1” 、 “任务2” 、“任务3” 都在主线程的主队列执行
    “任务1”首先执行   
    “任务2” 被添加到主队列  所以 “任务2” 会被添加到 “任务3”的后面  
    由于“任务2”不要求立马在当前线程同步执行任务 所以执行顺序是 :
      执行任务1
      执行任务3
      执行任务2
    
    答案:不会产生死锁
    

    例三:问题:以下代码是在主线程执行的,会不会产生死锁?

    - (void)question3{
    
        NSLog(@"执行任务1");
    
        dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_SERIAL);
        dispatch_async(queue, ^{ 
            NSLog(@"执行任务2");
            
            dispatch_sync(queue, ^{
                NSLog(@"执行任务3");
            });
        
            NSLog(@"执行任务4");
        });
        
        NSLog(@"执行任务5");
    }
    
    分析:首先把 “执行任务2”、 “执行任务3”、 “执行任务4”当成一个整体 
    简称 “执行任务A”
    
     “执行任务1”、 “执行任务A”、 “执行任务5” 这三个都在主线程执行 
    “任务1”首先执行 
    执行  “执行任务A”被放到自己手动创建的队列中且异步执行
    所以  “执行任务1”、 “执行任务A”、 “执行任务5” 的顺序是
    执行任务1
    执行任务A
    执行任务5
    
    然后再对“执行任务A”内部进行分析
    "执行任务2"、"执行任务3"、“执行任务4 ”被存放在 自己手动创建的队列中 
    “执行任务2”首先执行  
    “执行任务3”  被添加到自己手动创建的队列中  所以“执行任务3”会被添加到 “执行任务4”的后面  
    但是“执行任务3”又要求同步执行 所以在执行完 “执行任务2” 后要求立即执行“执行任务3”  
    但是“执行任务3” 又要等待“执行任务4” 执行完毕之后才能执行 这样就产生了死锁
    
    答案:会产生死锁
    

    例四:问题:以下代码是在主线程执行的,会不会产生死锁?

    - (void)question4{
    
     NSLog(@"执行任务1");
        
    dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("myqueu2", DISPATCH_QUEUE_SERIAL);
        
        dispatch_async(queue, ^{ 
            NSLog(@"执行任务2");
            
            dispatch_sync(queue2, ^{ 
                NSLog(@"执行任务3");
            });
            
            NSLog(@"执行任务4");
        });
        
        NSLog(@"执行任务5");
    }
    
    分析:首先把 “执行任务2”、 “执行任务3”、 “执行任务4”当成一个整体 
    简称 “执行任务A”
     “执行任务1”、 “执行任务A”、 “执行任务5” 这三个都在主线程执行 
    “执行任务A”被放到自己手动创建的队列中且异步执行
    所以  “执行任务1”、 “执行任务A”、 “执行任务5” 的顺序是
    执行任务1
    执行任务5
    执行任务A
    
    然后再对“执行任务A”内部进行分析
    "执行任务2"、“执行任务4 ”被存放在 myqueu 队列中
    "执行任务3"被存放在 myqueu2 队列中 且要求同步执行
    
    所以"执行任务2"、“执行任务3 ”、“执行任务4 ” 执行顺序是
    执行任务2
    执行任务3
    执行任务4
    
    整体执行顺序就是
    执行任务1
    执行任务5
    执行任务2
    执行任务3
    执行任务4
    
    
    答案:不会产生死锁
    

    例五:问题:以下代码是在主线程执行的,会不会产生死锁?

    - (void)question5{
    
        NSLog(@"执行任务1");
        
     dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_async(queue, ^{ // 0
            NSLog(@"执行任务2");
            
            dispatch_sync(queue, ^{ // 1
                NSLog(@"执行任务3");
            });
            
            NSLog(@"执行任务4");
        });
        
        NSLog(@"执行任务5");
    
    分析:首先把 “执行任务2”、 “执行任务3”、 “执行任务4”当成一个整体 
    简称 “执行任务A”
     “执行任务1”、 “执行任务A”、 “执行任务5” 这三个都在主线程执行 
    “执行任务A”被放到自己手动创建的并发队列中且异步执行
    所以  “执行任务1”、 “执行任务A”、 “执行任务5” 的顺序是
    执行任务1
    执行任务5
    执行任务A
    
    然后再对“执行任务A”内部进行分析
    由于myqueu 是并发队列所以 "执行任务2"、"执行任务3"、“执行任务4 ” 执行互不等待
    所以"执行任务2"、“执行任务3 ”、“执行任务4 ” 执行顺序是
    执行任务2
    执行任务3
    执行任务4
    
    
    整体执行顺序就是
    执行任务1
    执行任务5
    执行任务2
    执行任务3
    执行任务4
    
    答案:不会产生死锁
    }
    
    

    相关文章

      网友评论

          本文标题:iOS 常见面试题 --GCD

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