GCD学习

 GCD(Grand Dispatch)是异步执行的技术之一

 下面这个例子就是在后台线程中执行长时间处理,主线程使用该处理结果


dispatch_async(dispatch_get_global_queue(0,0), ^{

        /*

         长时间处理 比如 AR用画像识别

         数据库访问等

         长时间处理完毕,主线程使用该处理结果

         */

        NSLog(@"后台处理");

        dispatch_async(dispatch_get_main_queue(), ^{

        //只在主线程可以的处理

        //例如用户界面更新

            NSLog(@"主线程处理");

        });

    });


/*

 在导入GCD之前,Cocoa框架使用NSObject类的performSelectorInBackgroundwithObject实例方法和PerformSelectorOnMainThread实例方法等简单的多线程编程技术。

 下面用这两种方法实现上面的GCD

 */


//执行后台线程

-(void)lauchThreadByObject_performSelectouInBackground_withobject

{

[self performSelectorInBackground:@selector(doWork)withObject:nil

 ];


}

//后台线程处理

-(void)doWork

{

    /*

     长时间处理 比如 AR用画像识别

     数据库访问等

     长时间处理完毕,主线程使用该处理结果

     */

    [selfperformSelectorOnMainThread:@selector(doneWork)withObject:nilwaitUntilDone:NO];



}

//主线程处理方法

-(void)doneWork

{

   //只在主线程中处理,例如用户界面刷新等



}

//上面的方法确实是比用NSThread类进行多线程简单,但确实没有GCD更加方便和简单。而且还可以通过GCD提供的系统级线程管理提高执行效率。



/*

     多线程编程

     由于使用多线程程序可以在某个线程和其他线程之间反复多次进行上下文切换,因此看上去就像1CPU核能够并列的执行多个线程一样,而且在具有多个CPU核的情况下,就是真的提供了多个CPU核并行执行多个线程的技术。

     

     但是多线程实际上是一种容易发生各种问题的编程技术。

     比如多个线程更新相同的资源,会导致数据的不一致,(数据竞争)停止等待时间的线程会导致多个线程相互持续的等待(死锁)使用多线程会消耗大量内存等。

     尽管存在问题,也应当使用多线程编程,因为多线程编程保证应用程序的响应性能

     */


//GCDAPI

    

    //Dispatch  Queue

   /* dispatch_async(queue, ^{

    //想要执行的任务

    

    });

    开发者要做的只是定义想要执行的任务并追加到适当的Dispatch Queue

    Dispatch Queue 按照追加的顺序(FIFO)执行处理

    

    另外在执行处理时存在两种Dispatch Queue,一种等待现在执行中处理的Serial(连续的) Dispatch Queue,另一种是不等待现在执行处理的 Concurrent(并发的) Dispatch Queue

    */


//1.Dispatch_Queue_create

    //生成serial Dispatch Queue

    dispatch_queue_t mySerialDispatchQueue=dispatch_queue_create("com.example.gcd.mySerialDispatchQueue",NULL);

    //理论上来说,用该函数可以生成任意多个Dispatch Queue但是前面提到,过多使用多线程,会产生过多问题。 当为了比避免多线程问题之一:数据竞争就可以使用Serial Dispatch Queue当想并行执行不会发生数据竞争等问题时,使用Concurrent Dispatch Queue而且对于其来说,不管生成来说,由于XNU内核只是用有效管理的线程,因此不会发生serial Dispatch Queue等问题

    //生成Concurrent Dispatch Queue

    dispatch_queue_t  myConCurrentDispatchQueue=dispatch_queue_create("com.example.gcd.myConcurrentQueue",DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(myConCurrentDispatchQueue, ^{

    

        NSLog(@"block on myConcurrentDispatchQueue");

    });



 //2.Main Dispatch Queue/global Dispatch  Queue

    /*MAin Dispatch Queue 正如其名称一样,是在主线程中执行的Dispatch Queue,因为主线程只有一个,因此Main Dispatch Queue自然就是 serial Dispatch Queue追加到Main Dispatch Queue 的处理在主线程的runloop中执行,因此要将用户界面更新等一些不许在主线程中执行的处理追加到Main Dispatch Queue中执行。这与NSObject类的performSelectorOnMainThread该势力方法相同。

     

     Global Dispatch Queue是所有应用程序都能够使用的Concurrent Dispatch Queue只要获取global Dispatch Queue使用即可,其有四个优先级,高优先级(high Priority)默认优先级(default priority),低优先级(low priority),后台优先级(Background Priority

     

     */


 /*

     3.dispatch_set_target_queue

     该函数生成的Dispatch Queue 不管是serial Dispatch Queue还是concurrent Dispatch Queue都使用默认优先级。

     在必须将不可并行执行处理追加到多个serial Dispatch Queue,如果使用Dispatch_set_target_queue函数将目标制定为某一个serial Dispatch Queue,即可防止并行执行

     

     */



4.dispatch_after

     延迟处理

     

     */

    dispatch_time_t  time=dispatch_time(DISPATCH_TIME_NOW,2ull*NSEC_PER_SEC);

    dispatch_after(time, dispatch_get_main_queue(), ^{

        NSLog(@"waited  at least three seconds");


    });

    //上述ull表示unsigned long long或者

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        NSLog(@"waited  at least three seconds");

    });

    //注意Dispatch_after函数并不是在指定时间后执行处理,而只是在指定时间追加处理到Dispatch Queue。因此上述可能代码可能3s+1/60s,可能更长。Dispatch time函数通常用于计算相对时间,而Dispatch_walltime用于计算绝对时间。



 //5.dispatch Group  在追加到Dispatch Queue中得多个处理全部结束后,想执行结束处理 只使用一个serial Dispatch Queue时,只要将想执行的处理全部追加到serial Dispatch Queue中并在最后追加结束处理,即可实现。但是在使用Concurrent Dispatch Queue时或者同时使用多个Dispatch时,源码就会复杂   这种情况下,我们就用group

    //追加3blockglobal Dispatch Queue中,这些block执行完毕后,就会执行Main Dispatch Queue中结束处理使用的block

    dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    dispatch_group_t group =dispatch_group_create();

    dispatch_group_async(group, queue, ^{NSLog(@"blk1");});

    dispatch_group_async(group, queue, ^{NSLog(@"blk2");});


    dispatch_group_async(group, queue, ^{NSLog(@"blk3");});

    dispatch_group_notify(group,dispatch_get_main_queue(), ^{NSLog(@"done");});

//最后一句的第一个参数指定为要监视的Dispatch group 在追加到Dispatch group的全部处理结束后,将第三个参数的block追加到第二个参数的Dispatch Queue,在Dispatch_group_notify函数中不管指定什么样的Dispatch Queue属于Dispatch group的全部处理在追加指定的block时都已执行结束。

    

//由于多个线程并行执行,因此执行顺序不定,执行会发生变化,但是done一定是最后输出但是无论向什么样的Dispatch Queue 中追加处理,使用Dispatch group都可以监视这些处理执行的结束。一旦检测到所有处理执行结束,就可将结束的处理追加到Dispatch Queue中,这就是使用Dispatch group的原因。




//6.另外Dispatch group中也可使用Dispatch_group_wait函数仅等待全部处理执行结束

    

    

    dispatch_queue_t queuewait=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    dispatch_group_t groupwait =dispatch_group_create();

    dispatch_group_async(groupwait, queuewait, ^{NSLog(@"blk1");});

    dispatch_group_async(groupwait, queuewait, ^{NSLog(@"blk2");});

    

    dispatch_group_async(groupwait, queuewait, ^{NSLog(@"blk3");});

    dispatch_group_wait(groupwait,DISPATCH_TIME_FOREVER);

    //dispatch_group_wait参数指定为等待的时间(超时),它属于Dispatch_time_t类型的值。该代码用forever,意思为永久等待。只要Dispatch group的处理尚未执行结束,就会一直等待。中途不能取消。

    //等待间隔为1s

    dispatch_time_t time1=dispatch_time(DISPATCH_TIME_NOW,1ull*NSEC_PER_SEC);

    long result=dispatch_group_wait(groupwait, time1);

    if (result==0) {

        NSLog(@"Dispatch group全部处理结束");

    }else{

        NSLog(@"属于Dispatch的某一个处理还在进行中");

    

    }

    //推荐使用Dispatch_group_notify



//7.在访问数据库或者文件时,可以使用serial Dispatch Queue避免数据竞争的问题。

    //当然写入处理确实不可与其他的写入处理或者包含读取处理的其他某些处理并行处理,但是如果读取处理至于读取处理并行执行,那么多个并行执行就不会发生问题。即为了高效率的进行访问,读取处理追加到Concurrent Dispatch Queue中,写入处理在任何一个读取处理没有执行的状态下,追加到serial Dispatch Queue中即可。(在写入处理结束之前,读取处理不可执行)。

    

    //我们用Dispatch_barrier_async函数,该函数同Dispatch_queue_create函数生成的concurrent Dispatch Queue一起使用。

    //首先Dispatch_queue_create函数生成Concurrent Dispatch Queue,在Dispatch_async中追加处理。

    dispatch_queue_t queuebarrier=dispatch_queue_create("com.example.gcd.forBarrier",DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queuebarrier, ^{NSLog(@"blk0_for_reading");});

    dispatch_async(queuebarrier, ^{NSLog(@"blk1_for_reading");});

    dispatch_async(queuebarrier, ^{NSLog(@"blk2_for_reading");});

    dispatch_async(queuebarrier, ^{NSLog(@"blk3_for_reading");});

    dispatch_async(queuebarrier, ^{NSLog(@"blk4_for_reading");});

    dispatch_barrier_async(queuebarrier, ^{NSLog(@"blk_for_writting");});

    dispatch_async(queuebarrier, ^{NSLog(@"blk5_for_reading");});


    dispatch_async(queuebarrier, ^{NSLog(@"blk6_for_reading");});

    dispatch_async(queuebarrier, ^{NSLog(@"blk7_for_reading");});

    dispatch_async(queuebarrier, ^{NSLog(@"blk8_for_reading");});

   //Dispatch_barrier_aysync函数会等待追加到concurrent Dispatch Queue上得并行执行的全部处理结束之后,在将制定的处理追加到该concurrent Dispatch Queue中,然后在Dispatch Queue才恢复一般的动作,追加到该Concurrent Dispatch Queue的处理又开始并行执行

    //使用Concurrent Dispatch QueueDispatch_barrier_aysnc函数可执行高效率的数据库访问和文件访问。



//8.Dispatch_sync 意味着非同步,就是将block非同步的追加到制定的Dispatch Queue其不做任何等待。

    //下面我们执行Main Dispatch Queue时,使用另外的县城global Dispatch Queue进行处理,处理结束后立即使用所得到的结果,这种情况下,可以使用Dispatch_sync函数

    dispatch_queue_t queuesync=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    dispatch_sync(queuesync, ^{NSLog(@"处理");});

    //Dispatch_sync可以简化源代码,但是也极易引起代码,死锁

    


 /*

   9.  dispatch_apply 函数是将dispatch_sync函数和dispatch_group关联的API,该函数按照指定的次数将指定的block追加到dispatch queue中,并等待全部处理结束。

     第一个参数为重复次数,第二个参数为追加对象的dispatch queue,第三个处理为追加的处理。

     */

    dispatch_apply(10,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^(size_t index){

        NSLog(@"%zu",index);

    });

    NSLog(@"done");

    

    

    NSArray *array=[[NSArrayalloc]initWithObjects:@"1",@"2",@"3",nil];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

   //nsarray的类对象的所有元素执行处理。

        dispatch_apply([arraycount], dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^(size_t index){

            //并列处理包含在nsarray对象的全部对象。

            NSLog(@"%zu: %@",index,[arrayobjectAtIndex:index]);

        

        });

        

        //dispatch_apply函数中的全部处执行结束

        

        //Main dispatch queue中非同步执行。

        dispatch_async(dispatch_get_main_queue(), ^{

        

        // Main dispatch queue中执行处理  用户界面更新等

        });

    

    });



 /*

   10.  dispatch_suspend/dispatch_resume

     当追加大量处理到dispatch_queue时,在追加处理过程中,有时希望不执行已经追加的处理,

     这种情况下,可以挂起 dispatch queue即可,当可以执行时在恢复。

     dispatch_suspend(queue);

     

     //恢复指定的dispatch queue

     dispatch_resume(queue)

     

     */


  /* 11. dispatch_semaphore 

     因为并行处理更新数据时,会产生数据不一致的情况,可以使用serial dispatch queuedispatch_barrier_aysnc可避免这类问题,但是可以进行更加细粒度的排他控制

     但暂时用不到,不做介绍、

     

     */


/*

     dispatch_once 保证在应用程序执行中只执行一次指定处理的API

     

     

     */

    

    

    //12原来用来进行初始化的源码。在多核CPU的情况下,在正在更新表示是否初始化的标志时,可能进行多次初始化处理

    static int  initialized=NO;

    if (initialized==NO) {

        //初始化

        initialized=YES;

    }

    

    

    //如果使用dispatch_once函数,则源码可以写为

    static dispatch_once_t pred;

    dispatch_once(&pred,^{

    //初始化

    

    });

    //该代码在多线程情况下,也可以保证百分百安全。这就是所说的单例模式。


    //13dispatch I/O可以提高文件的可读性,暂不做介绍。


注: NSOperationQueue与GCD的区别

NSOperation是用GCD构建,是GCD的高级抽象

GCD只支持FIFO队列,而加入NSOperation队列的操作可以被重新排序,即重新设置优先级

NSOperationQueue支持在操作之间设置依赖关系,而GCD不支持。

NSOperationQueue兼容KVO,这意味着你可以观察任务的状态。

NSOperationQueue的执行速度比GCD慢。

本文内容是学习高级Object-c编程一书所写



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值