【读书笔记】Objective-C高级编程--GCD的API

来源:互联网 发布:提词器软件下载 编辑:程序博客网 时间:2024/06/05 11:56

1,Dispatch Queue

Dispatch Queue是执行处理的等待队列。按照FIFO执行处理。

Dispatch Queue分为等待现在执行中处理的Serial Dispatch Queue和不等待现在执行中处理的Concurrent Dispatch Queue。

Serial Dispatch Queue是当前一个执行结束后才执行后一个。Concurrent Dispatch Queue则不用等,但是要根据CPU核数和负荷等系统状态决定。OSX和iOS的核心XNU内核决定应当使用的线程数,并只生产所需的线程执行处理。当处理结束,应当执行的处理数减少时,XNU内核会结束不再需要的线程。XNU内核仅使用Concurrent Dispatch Queue便可完美地管理并行执行多个处理的线程。

2,dispatch_queue_create

第一种方法是通过GCD的API生成Dispatch Queue。

串行:dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.serialDispatchQueue", NULL);

虽然serial dispatch queue和concurrent dispatch queue受到系统资源限制,但是用dispatch_queue_create函数可以生成任意多个dispatch queue。当生成多个serial dispatch queue时,各个将并行执行。虽然一个serial dispatch queue中同时只能执行一个追加处理,但是同时执行多个处理。

只在为了避免多线程编程问题之一----多个县城更新相同资源导致数据竞争时使用serial dispatch queue。(数组)

虽然serial dispatch queue比concurrent dispatch queue能生成更多的线程,但决不能生成大量serial dispatch queue。

当想并行执行不发生数据竞争等问题的处理时,使用concurrent dispatch queue。对其而言,不管生成多少,由于XNU内核只使用有效管理的线程,所以不会出现无数个线程。

并行 dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.concurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);

生成的dispatch queue必须自己释放,不管是否是arc机制。

3,Main Dispatch Queue/ Global Dispatch Queue

第二种方法是获取系统标准提供的Dispatch Queue。

Main Dispatch Queue是串行的,因为主线程只有一个。同performSelectorOnMainThread。

Global Dispatch Queue是所有应用程序都能够使用的Concurrent Dispatch Queue。没必要通过dispatch_queue_create函数逐个生成Concurrent Dispatch Queue,只要获取Global Dispatch Queue使用即可。它有四个执行优先级,分别是高优先级,默认优先级,低优先级和后台优先级。通过XNU内核管理的用于Global Dispatch Queue的线程,将各自使用的Global Dispatch Queue的执行优先级作为线程的执行优先级使用。但是通过XNU内核用于Global Dispatch Queue的线程并不能保证实时性。

dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();

dispatch_queue_t globalHighQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

4,dispatch_set_target_queue

dispatch_queue_create函数生成的dispatch queue不管是serial dispatch queue还是concurrent dispatch queue,都使用与默认优先级global dispatch queue相同执行优先级的线程。而变更生成的dispatch queue的执行优先级要使用dispatch_set_target_queue函数。在后台执行动作处理的serial dispatch queue的生成方法如下:

dispatch_queue_t serialDispatchQueue = dispatch_queue_create("SerialQueue", NULL);

dispatch_queue_t globalDispatchQueueBG = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

dispatch_set_target_queue(serialDispatchQueue, globalDispatchQueueBG);

制定要变更执行优先级的Dispatch Queue为dispatch_set_target_queue函数的第一个参数,指定与要使用的执行优先级相同的GlobalDispatch Queue为第二个参数。第一个参数如果指定系统提供的Main Dispatch Queue和Global Dispatch Queue则不知道,因此这些均不可指定。这样不仅可变更Dispatch Queue的执行优先级,还可以作成Dispatch Queue的执行阶层。如果在多个Serial Dispatch Queue中用dispatch_set_target_queue函数指定目标为某一个serial dispatch queue,那么原本应并行执行的多个serial dispatch queue,在目标serial dispatch queue上只能同时执行一个处理。

5,dispatch_after

经常会有这样情况,希望在3秒后执行处理。可能不仅限于3秒。

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

dispatch_after(time, dispatch_get_main_queue(), ^{

//

});

dispatch_after函数并不是在指定时间后执行处理,而只是在指定时间追加处理到dispatch queue。

dispatch_time函数能够获取从第一个参数dispatch_time_t类型值中指定的时间开始,第二个参数指定的毫微秒单位时间后的时间。

6,Dispatch Group

在追加到Dispatch Queue中的多个处理全部结束后想执行结束处理,使用到Dispatch Group。

例如:

//CGD一组任务

    dispatch_group_t group=dispatch_group_create();

    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{

        for (int i=0; i<20; i++) {

            NSLog(@"%d",i);

        }


    });

    

    //完成后通知

    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{

        NSLog(@"notify");

    });

无论向什么样的Dispatch Queue中追加处理,使用Dispatch Group都可监视这些处理执行的结束。一旦检测到所有处理执行结束,就可以将结束追加到DIspatch Queue中。

其中DISPATCH_TIME_FOREVER意味着永久等待,只要属于Dispatch Group的处理尚未结束,就会一直等待,中途不能取消。

7,dispatch_barrier_async

在访问数据库或文件时,使用serial dispatch queue可避免数据竞争的问题。写入处理确实不可与其他的写入处理及包含的读取处理的其他某些处理并行执行。也就是说为了高效地进行访问,读取处理追加到Concurrent Dispatch Queue中,写入处理在人一个读取处理没有执行的状态下,追加到Serial Dispatch Queue中即可。GCD为我们提供了dispatch_barrier_async来处理这个问题。

dispatch_queue_t queue = dispatch_queue_create (

     "com.example.gcd.ForBarrier" , DISPATCH_QUEUE_CONCURRENT ) ;

 dispatch_async ( queue , blk0_for_reading ) ;

dispatch_async ( queue , blk1_for_reading ) ;

dispatch_async ( queue , blk2_for_reading ) ;

dispatch_async ( queue , blk3_for_writing ) ;

dispatch_async ( queue , blk4_for_reading ) ;

dispatch_async ( queue , blk5_for_reading ) ;

dispatch_async ( queue , blk6_for_reading ) ;

dispatch_async ( queue , blk7_for_reading ) ;

dispatch_release ( queue ) ;

这样容易出错。

dispatch_async ( queue , blk0_for_reading ) ;

dispatch_async ( queue , blk1_for_reading ) ;

dispatch_async ( queue , blk2_for_reading ) ;

dispatch_async ( queue , blk3_for_reading ) ;

dispatch_barrier_async ( queue , blk_for_writing ) ;

dispatch_async ( queue , blk4_for_reading ) ;

dispatch_async ( queue , blk5_for_reading ) ;

dispatch_async ( queue , blk6_for_reading ) ;

dispatch_async ( queue , blk7_for_reading ) ;

dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行。使用Concurrent和dispatch_barrier_async函数可以高效率地数据库访问和文件访问。

8,dispatch_sync

dispatch_async函数不做任何等待。反之dispatch_sync会一直等待。

9,dispatch_apply

它是dispatch_sync函数和dispatch group的关联API。该函数按指定的次数将制定的block追加到指定的dispatch queue中,并等待全部执行结束。因为在global dispatch queue中执行处理,所以各个处理的执行时间不定。但是输出结果中最后的done必定在最后的位置上。另外dispatch_apply函数和dispatch_sync函数相同,会等待处理执行结束,因此推荐在dispatch_async函数中非同步地执行dispatch_apply函数。

10,dispatch_suspend/dispatch_resume

当追加大量处理到dispatch queue时,在追加处理的过程中,有时希望不执行已追加的处理。这时候就需要挂起dispatch queue。

11,dispatch_once

函数保证在应用程序执行中只执行一次制定出来的api。




0 0