iOS线程之GCD初探

作者: _兜兜转转_ | 来源:发表于2016-03-28 17:45 被阅读922次

    简述:
    说道线程,离不开并行和串行,所谓并行,就是100赛跑,每个赛道就是一个线程,每个线程之间互不影响,同时都可以运行事件,就是10个赛道都可以有运动员跑步了,谁跑的慢或者跑的快,都不影响其他的人。串行就不一样了,串行是1个赛道10个运动员再跑接力赛,第一个跑到终点第二个在接着跑,依次类推,前边的不走,后边的也走不了的,所以串行上面的事件是一个一个运行的,同时只能是一个人再跑。

    在iOS或者OS里面,一般用GCD就能处理较多的事务,下面就谈一下GCD的用法。

    什么是GCD?

    全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
    纯C语言,提供了非常多强大的函数

    methodList info

    
    //获取主线程 就是更新UI的线程
    dispatch_queue_t dispatch_get_main_queue(void);
    
     //获取全局队列
    dispatch_queue_t dispatch_get_global_queue( long identifier, unsigned long flags);
    
    //创建一个队列 名字是label 属性可以写为NULL  
    dispatch_queue_t dispatch_queue_create( const char *label dispatch_queue_attr_t attr);
    dispatch_release(queue)//释放队列
    
    //获取代码现在运行的queue
    dispatch_queue_t dispatch_get_current_queue( void);
    
     //获取队列的名字
    const char * dispatch_queue_get_label(dispatch_queue_t queue);
    
    //异步把代码块block交给queue队列中处理
    dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
    
    // 同步将block加入到queue中并且执行。
    void dispatch_sync( dispatch_queue_t queue, dispatch_block_t block);
    
     //block 在指定时间在queue中执行
    void dispatch_after( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
    
     
    //几个调度事件同事加入到queue中去,最好是全局队列才行。
    void dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)( size_t));
    
    // block 是否执行过
    void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
     
    //在分组group中的queue队列执行block
    void dispatch_group_async( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
    
    //创建线程分组
    dispatch_group_t dispatch_group_create( void);
    
     //分组的计数+1
    void dispatch_group_enter( dispatch_group_t group);
    
    //分组计数 -1
    void dispatch_group_leave( dispatch_group_t group);
    
    // 当分组中的事务处理完了执行block
    void dispatch_group_notify( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
    
    //等待timeout时间后执行 group中的事务
    long dispatch_group_wait( dispatch_group_t group, dispatch_time_t timeout);
    
     //并行状态下 queue前面的并行事务处理完成了在执行block,然后执行下边的并行代码
    //比如 ABCDEF D事务等到ABC都完成了在执行EF事务的
    void dispatch_barrier_async( dispatch_queue_t queue, dispatch_block_t block);
    
    

    实战演练全局队列

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(queue, ^{
            //异步执行
            dispatch_sync(dispatch_get_main_queue(), ^{
                //这里面更新UI
            });
        });
        dispatch_sync(queue, ^{
           //同步执行
        });
    

    自定义队列

    dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_SERIAL);
        //
    //#define DISPATCH_QUEUE_SERIAL   同步队列
    //#define DISPATCH_QUEUE_CONCURRENT 异步队列
        dispatch_async(queue, ^{
            NSLog(@"下载图片1=====%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"下载图片2=====%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"下载图片3=====%@",[NSThread currentThread]);
        });
        NSLog(@"main:%@",[NSThread mainThread]);
    当queue属性为 DISPATCH_QUEUE_CONCURRENT输出:
    **2016-03-28 16:53:25.848 GCD_Demo[12338:347984] ****下载图片****3=====<NSThread: 0x7fabda100250>{number = 4, name = (null)}**
    **2016-03-28 16:53:25.848 GCD_Demo[12338:347982] ****下载图片****2=====<NSThread: 0x7fabda2008a0>{number = 3, name = (null)}**
    **2016-03-28 16:53:25.848 GCD_Demo[12338:347937] main:<NSThread: 0x7fabd8c04ee0>{number = 1, name = main}**
    **2016-03-28 16:53:25.848 GCD_Demo[12338:347981] ****下载图片****1=====<NSThread: 0x7fabd8c0a010>{number = 2, name = (null)}** 线程达到了4个
    当queue属性为DISPATCH_QUEUE_SERIAL输出:
    **2016-03-28 16:46:54.501 GCD_Demo[12272:344348] main:<NSThread: 0x7fd379704cf0>{number = 1, name = main}**
    **2016-03-28 16:46:54.501 GCD_Demo[12272:344382] ****下载图片****1=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
    **2016-03-28 16:46:54.502 GCD_Demo[12272:344382] ****下载图片****2=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
    **2016-03-28 16:46:54.502 GCD_Demo[12272:344382] ****下载图片****3=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
    线程只有2个
    
    

    多个异步线程问题

    # 当ABC 3个异步线程,要求前两个个执行完再去执行后面的三个的时候例子:
         dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
    
        dispatch_async(queue, ^{
            NSLog(@"queue1 begin");
            sleep(2);
            NSLog(@"queue1 end");
        });
        dispatch_async(queue, ^{
            NSLog(@"queue2 begin");
            sleep(2);
            NSLog(@"queue2 end");
        });
        dispatch_barrier_sync(queue, ^{
            NSLog(@"main:%@",[NSThread mainThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"queue3 begin");
            sleep(2);
            NSLog(@"queue3 end");
        });
    输出:
    
    **2016-03-28 17:01:01.319 GCD_Demo[12463:353702] queue2 begin**
    **2016-03-28 17:01:01.319 GCD_Demo[12463:353703] queue1 begin**
    **2016-03-28 17:01:03.324 GCD_Demo[12463:353703] queue1 end**
    **2016-03-28 17:01:03.324 GCD_Demo[12463:353702] queue2 end**
    **2016-03-28 17:01:03.325 GCD_Demo[12463:353657] main:<NSThread: 0x7f97ea604bf0>{number = 1, name = main}**
    **2016-03-28 17:01:03.325 GCD_Demo[12463:353702] queue3 begin**
    **2016-03-28 17:01:05.330 GCD_Demo[12463:353702] queue3 end**
    

    线程分组

    # 当多个任务同时进行的时候,也可以用group,ABCD任务进行完成的时候,最后在执行task。
     
    
      dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, queue, ^{
            
            NSLog(@"task1 begin");
            sleep(2);
            NSLog(@"task1 end");
        });
        
        dispatch_group_async(group, queue, ^{
            
            NSLog(@"task2 begin");
            sleep(2);
            NSLog(@"task2 end");
        });
        dispatch_group_notify(group, queue, ^{
            NSLog(@"=================");
        });
        dispatch_group_async(group, queue, ^{
            
            NSLog(@"task3 begin");
            sleep(2);
            NSLog(@"task3 end");
        });
        
        dispatch_group_async(group, queue, ^{
            
            NSLog(@"task4 begin");
            sleep(2);
            NSLog(@"task4 end");
        });
    输出:
    **2016-03-28 17:08:45.002 GCD_Demo[12557:357162] task1 begin**
    **2016-03-28 17:08:45.002 GCD_Demo[12557:357164] task4 begin**
    **2016-03-28 17:08:45.002 GCD_Demo[12557:357161] task2 begin**
    **2016-03-28 17:08:45.002 GCD_Demo[12557:357163] task3 begin**
    **2016-03-28 17:08:47.005 GCD_Demo[12557:357162] task1 end**
    **2016-03-28 17:08:47.005 GCD_Demo[12557:357163] task3 end**
    **2016-03-28 17:08:47.005 GCD_Demo[12557:357164] task4 end**
    **2016-03-28 17:08:47.005 GCD_Demo[12557:357161] task2 end**
    **2016-03-28 17:08:47.006 GCD_Demo[12557:357161] =================**
    一个组内的所有任务都进行完了才会执行task的函数。
    
    
    # 分组多任务等待 ABCDEF ,ABCD执行5秒,5秒之后就执行EF任务,不管ABCD是否成功。
    
        dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, queue, ^{
            
            NSLog(@"task1 begin");
            sleep(2);
            NSLog(@"task1 end");
        });
        
        dispatch_group_async(group, queue, ^{
            
            NSLog(@"task2 begin");
            sleep(2);
            NSLog(@"task2 end");
        });
        dispatch_group_notify(group, queue, ^{
            NSLog(@"=================");
        });
        dispatch_group_async(group, queue, ^{
            
            NSLog(@"task3 begin");
            sleep(6);
            NSLog(@"task3 end");
        });
        dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC)));
        NSLog(@"all end");
        dispatch_group_async(group, queue, ^{
            
            NSLog(@"task4 begin");
            sleep(2);
            NSLog(@"task4 end");
        });
    输出:
    # 代码执行到wait的时候会等待5秒之后再执行wait下边的代码,和sleep有点相似。
    **2016-03-28 17:26:31.335 GCD_Demo[12745:366983] task3 begin**
    **2016-03-28 17:26:31.335 GCD_Demo[12745:366978] task1 begin**
    **2016-03-28 17:26:31.335 GCD_Demo[12745:366979] task2 begin**
    **2016-03-28 17:26:33.340 GCD_Demo[12745:366978] task1 end**
    **2016-03-28 17:26:33.340 GCD_Demo[12745:366979] task2 end**
    **2016-03-28 17:26:36.336 GCD_Demo[12745:366894] all end**
    **2016-03-28 17:26:36.336 GCD_Demo[12745:366979] task4 begin**
    **2016-03-28 17:26:37.340 GCD_Demo[12745:366983] task3 end**
    **2016-03-28 17:26:38.342 GCD_Demo[12745:366979] task4 end**
    **2016-03-28 17:26:38.342 GCD_Demo[12745:366983] =================**
    

    同时处理多数据不管顺序

              dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        
              /*! dispatch_apply函数说明
               10      *
               11      *  @brief  dispatch_apply函数是dispatch_sync函数和Dispatch Group的关联API
               12      *         该函数按指定的次数将指定的Block追加到指定的Dispatch Queue中,并等到全部的处理执行结束
               13      *
               14      *  @param 10    指定重复次数  指定10次
               15      *  @param queue 追加对象的Dispatch Queue
               16      *  @param index 带有参数的Block, index的作用是为了按执行的顺序区分各个Block
               17      *
               18      */
              dispatch_apply(10, queue, ^(size_t index) {
                      NSLog(@"%d", index);
                  
                  });
              NSLog(@"done");
    输出:
    # 这个和上边讲的分组类似,多事务处理,处理结束后再执行代码。
    # 这个是同步的,代码按顺序执行,分组的是异步执行的block
    **2016-03-28 17:36:35.698 GCD_Demo[12857:372458] 1**
    **2016-03-28 17:36:35.698 GCD_Demo[12857:372463] 5**
    **2016-03-28 17:36:35.698 GCD_Demo[12857:372429] 4**
    **2016-03-28 17:36:35.698 GCD_Demo[12857:372464] 6**
    **2016-03-28 17:36:35.698 GCD_Demo[12857:372465] 7**
    **2016-03-28 17:36:35.698 GCD_Demo[12857:372462] 2**
    **2016-03-28 17:36:35.698 GCD_Demo[12857:372457] 0**
    **2016-03-28 17:36:35.698 GCD_Demo[12857:372461] 3**
    **2016-03-28 17:36:35.699 GCD_Demo[12857:372458] 8**
    **2016-03-28 17:36:35.699 GCD_Demo[12857:372429] 9**
    **2016-03-28 17:36:35.699 GCD_Demo[12857:372429] done**
        
    

    参考文章:Grand Central Dispatch (GCD) Reference
    GCD提供的接口蛮多的,适用场景还是要熟练掌握,才能运用自如。
    更多文章:www.fgyong.cn

    相关文章

      网友评论

        本文标题:iOS线程之GCD初探

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