牛逼的中枢调度器

作者: 来金德瑞 | 来源:发表于2016-07-18 12:00 被阅读68次

    简介

    • GCD是苹果公司为多核的并行运算提出的解决方案
    • GCD会自动利用更多的CPU内核(比如双核、四核)
    • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
    • GCD是纯C语言实现的,提供了非常多强大的函数

    核心概念

    GCD中有两个核心概念:

    • 任务:执行什么操作
    • 队列:用来存放任务

    GCD的使用步骤

    1. 指定任务,确定想做的事情
    2. 将任务添加到队列中,GCD会自动将队列中的任务取出来放到对应的线程中执行。队列的取出遵循队列的FIFO原则:先进先出,后进后出

    执行任务

    GCD中有两个可以用来执行任务的函数

    • 用同步的方式执行任务:只能在当前线程中执行,不会开其他线程
    //queue:队列;block:任务
    void dispatch_sync(dispatch_queue_t queue,dispatch_block_t block);
    
    • 用异步的方法执行任务:可以在新的线程中执行任务,具备开启新线程的能力
    //queue:队列;block:任务
    void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
    

    队列的类型

    GCD中的队列可以分为两大类型:

    • 并发队列(concurrent dispatch queue):可以让队列任务并发(同时)执行(自动开启多个线程同时执行任务),并发功能只有在异步函数(dispatch_asyns)中才有效

      • GCD默认已经提供了全局的并发队列,提供整个应用使用,不需要手动创建。

        dispatch_queue_t dispatch_get_global_queue(dispatch_queue_t
        priority,unsigned long flags);
        //priority:队列的优先级,flags:此参数暂时没有使用,传0即可
        
    • 串行队列(serial dispatch queue):让任务一个接着一个地执行(一个任务执行完毕后,在执行下一个任务)。GCD有两种方式获得串行队列

      • 使用dispatch_queue_create函数手动创建串行队列
      dispatch_queue_t dispatch_queue_create(const char
      *label,dispatch_queue_create_attr_t attr);
      //label:队列名称,attr:队列属性,一般用NULL即可
      
      • 使用主队列(跟主线程相关的队列):主队列是GCD中的自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行。
      dispatch_queue_t dispatch_get_main_queue(void);
      
        *注意*:
        
        1.  //主队列(添加到主队列中的任务,都会自动添加到主线程中执行)
        
            dispatch_queue_t queue = dispatch_get_main_queue();
        2.  //添加任务到主队列中异步执行,该异步功能失效
        
            dispatch_async(queue,^{任务});
        3.  //添加任务到主队列中同步执行,改同步功能会卡死
        
            Dispatch_sync(queue,^{任务});
      

    总结

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

      dispatch_sync: 同步,不具备开启线程的能力

      dispatch_async:异步,具备开启线程的能力

    • 并发和串行主要影响任务的执行方式:并发是多个任务同时执行;串行是一个执行完毕后,在执行下一个任务。

      //获得全局的并发队列
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
      //创建一个串行队列
      dispatch_queue_t queue = dispatch_queue_create("name.queue",NULL);
      //主队列(添加到主队列中的任务,都会自动方法主线程中执行)
      dispatch_queue_t queue = dispatch_get_main_queue();
      

    使用例子

    1. 同步函数+主队列
    -(void)syncMain{
        NSLog(@"begin");
        
        dispatch_queue_t queue = dispatch_get_main_queue();
        
        dispatch_sync(queue,^{
            NSLog(@"1---%@",[NSThread currentThread]);
        });
        dispatch_sync(queue,^{
            NSLog(@"2---%@",[NSThread currentThread]);
        });
        dispatch_sync(queue,^{
            NSLog(@"3---%@",[NSThread currentThread]);
        });
        
        NSLog(@"end");
        
        //注意:使用sync函数往当前队列中添加任务,会卡住当前的串行队列,除了begin其他都不会被打印。
    }
    
    1. 异步函数+主队列
    - (void)asyncMain
    {
        
        dispatch_queue_t queue = dispatch_get_main_queue();
        
        dispatch_async(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
        
        //注意:不会开启新线程。只会在主队列中执行,失去了异步函数的功能。
    }
    
    1. 同步函数+串行队列
    -(void)syncSerial{
    
        dispatch_queue_t queue = dispatch_queue_create("com.queue",DISPATCH_QUEUE_SERIAL);
        
        dispatch_sync(queue,^{
            NSLog(@"1---%@",[NSThread currentThread]);
        })
        dispatch_sync(queue,^{
            NSLog(@"2---%@",[NSThread currentThread]);
        })
        dispatch_sync(queue,^{
            NSLog(@"3---%@",[NSThread currentThread]);
        })
        
        //注意:不会开启新的线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务
    }
    
    1. 异步函数+串行队列
    - (void)asyncSerial
    {
        
        dispatch_queue_t queue = dispatch_queue_create("com.queue", DISPATCH_QUEUE_SERIAL);
        
        dispatch_async(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
        
        注意:会开启新的线程,但是任务是串行的,执行完一个任务,再执行下一个任务
    }
    
    1. 同步函数+并发队列
    - (void)syncConcurrent
    {
        
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        dispatch_sync(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
        
        //注意:不会开启新的线程。串行执行任务。
    }
    
    
    1. 异步函数+并发队列:可以同时开启多条线程,是最常用的方式
    - (void)asyncConcurrent
    {
        // 1.获得全局的并发队列
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        // 2.将任务加入队列
        dispatch_async(queue, ^{
            for (NSInteger i = 0; i<10; i++) {
                NSLog(@"1-----%@", [NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (NSInteger i = 0; i<10; i++) {
                NSLog(@"2-----%@", [NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (NSInteger i = 0; i<10; i++) {
                NSLog(@"3-----%@", [NSThread currentThread]);
            }
        });
        
    

    各种队列的执行效果

    全局并发队列 手动创建串行队列 主队列(串行队列)
    同步(sync) 不会开启新线程串行执行任务 没有开启新线程串行执行任务 没有开启新线程串行执行任务会卡死
    异步(async) 有开启新线程并发执行任务 有开启新线程串行执行任务 没有开启新线程串行,执行任务

    GCD的其他用法

    用法一

    // 作用:在并行队列中,等待前面的所有并行操作完成,然后执行dispatch_barrier_async中的操作,然后恢复原有执行状态,继续并行执行
    void dispatch_barrier_async(dispatch_queue_t queue,dispatch_block_t block);
    

    用法二

    //作用:延迟执行
    void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
    

    用法三

    //作用:block中的代码块只被执行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        //需要执行的代码块
    });
    

    用法三

        //作用:文件剪切,快速迭代
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        NSString *from = @"/Users/Anthony/Desktop/From";
        NSString *to = @"/Users/Anthony/Desktop/To";
        
        NSFileManager *mgr = [NSFileManager defaultManager];
        NSArray *subPaths = [mgr subpathsAtPath:from];
        
        dispatch_apply(subPaths.count, queue, ^(size_t index) {
           
            NSString *subPath = subPaths[index];
            NSString *fromFullPath = [from stringByAppendingPathComponent:subPath];
            NSString *toFullPath = [to stringByAppendingPathComponent:subPath];
            
            [mgr moveItemAtPath:fromFullPath toPath:toFullPath error:nil];
            
            NSLog(@"%@--%@",[NSThread currentThread],subPath);
        });
        
    
    

    用法四

    //队列组
    dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);�dispatch_group_t group = dispatch_group_create();
    //下载图片
    dispatch_group_async(dispatch_group_t group,dispath_queue_t queue,^{});
    //(保证执行完组里面的所有任务之后,再执行notify函数里面的block)
    dispatch_group_notify(dispatch_group_t group,
    dispatch_queue_t queue,
    dispatch_block_t block);
    

    相关文章

      网友评论

        本文标题:牛逼的中枢调度器

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