美文网首页
GCD(调度队列任务)

GCD(调度队列任务)

作者: _涼城 | 来源:发表于2016-07-13 14:28 被阅读67次

          GCD提供和管理FIFO队列,应用程序可以在块对象的形式提交的任务。提交给调度队列的块在系统完全由系统管理的线程池上执行。对执行任务执行的线程没有保证。GCD提供三种队列:

    主要任务:任务在应用程序的主线程上连续执行

    并行:工作队按照先进先出的顺序,但同时运行,可以以任何顺序完成。

    串行:任务执行一个在先进先出的顺序一次

           并发队列同时执行大量的任务。GCD自动创建四个并发调度队列(三之前的iOS 5和OS X v10.7)是全局应用程序,只有它们的优先级区分。您的应用程序请求这些队列使用dispatch_get_global_queue功能。因为这些并发队列是全局到您的应用程序,您不需要保留和释放它们,保留和释放对它们的调用都将被忽略。在OS X v10.7或以后或iOS 4.3之后,您还可以创建您自己的代码模块使用额外的并发队列。

          使用串行队列,以确保任务在可预测的顺序中执行。这是一个很好的做法,以确定一个特定的目的为每个串行队列,如保护一个资源或同步关键过程。您的应用程序必须显式创建和管理串行队列。它可以创建尽可能多的他们,但应避免使用它们,而不是并发队列,只是为了同时执行许多任务。

    1.异步执行

       (1) 为调度队列中的异步执行提交一个块,并立即返回。

    void dispatch_async( dispatch_queue_t queue, dispatch_block_t block);

       (2)提交一个应用程序定义的函数,用于在调度队列中异步执行,并立即返回。

    void dispatch_async_f( dispatch_queue_t queue, void *context, dispatch_function_t work);


    2.同步执行

        提交一个块对象,用于调度队列的执行,并等待该块完成,意味着当前线程停止。

    void dispatch_sync( dispatch_queue_t queue, dispatch_block_t block);

          假设,执行 Main Dispatch Queue 时,使用另外的线程 Global Dispatch Queue 进行处理,处理结束后立即使用所得到的结果。在这种情况下使用 dispatch_sync 函数。

    dispatch_queue_t queue = 

           dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY,0);

    dispatch_sync(queue,^{/** 处理 */});

          正因为 dispatch_sync 函数使用简单,所以也容易引起死锁问题。

          所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

    例如,如果在主线程执行以下源代码就会死锁。

    dispatch_queue_t queue = dispatch_get_main_queue();

    dispatch_sync(queue,^{NSLog(@"Hello?");});


    3.将用于在指定的时间执行块。


    void dispatch_after( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

        在3s 后将指定的 Block 追加到 Main Dispatch Queue 中的源代码如下:

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

    dispatch_after(time,dispatch_get_main_queue(),^(

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

    ));

          第一个参数用 dispatch_time 函数或 dispatch_walltime 函数生成。dispatch_time 函数通常用于计算相对时间,而 dispatch_walltime 函数用于计算绝对时间。

          需要注意的是,dispatch_after 函数并不是在指定时间后执行处理,而只是在指定时间内追加处理到 Dispatch Queue。此源代码和在3s 后用 dispatch_async 函数追加 Block 到 Main Dispatch Queue 的相同。


    4.提交一个块为多个调用调度队列。

    void dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)( size_t));

          dispatch_apply 函数是 dispatch_sync 函数和 Dispatch Group 的关联 API。该函数按指定的次数将指定的 Block 追加到指定的 Dispatch Queue 中,并等待全部处理执行结束。

         第一个参数为重复次数,第二个参数为追加对象的 Dispatch Queue,第三个参数为追加的处 理。例如要对 NSArray 类对象的所有元素执行某些处理时,不必编写 for 循环部分。

    dispatch_queue_t queue =

          dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    dispatch_apply([array count],queue,^(size_t index){

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

    });

          另外,由于 dispatch_apply 函数也与 dispatch_sync 函数相同,会等待处理执行结束,因此推荐在 dispatch_async 函数中非同步地执行 dispatch_apply 函数。

    dispatch_queue_t queue = 

          dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    /**在 Global Dispatch Queue 中非同步执行  */

    dispatch_async(queue,^{

    /**Global Dispatch Queue, 等待dispatch_apply 全部处理执行结束*/

    dispatch_apply([array count],queue,^(size_t index){

    /** 并行处理包含在 NSArray 对象的全部对象 */

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

    });

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

    /** 在 Main Dispatch Queue 中非同步执行 */

    dispatch_asycn(dispatch_get_main_queue(),^{

    /** 在 Main Dispatch Queue 中执行处理用户更新界面等 */

        NSLog(@"done");

    });

    });



    5.在整个应用程序周期内只执行一次。

    void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);

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

    static dispatch_once_t pred;

    dispatch_once(&pred,^{

    /**初始化  */

    });

    通过 dispatch_once 函数可以使得在多线程环境下执行,也可以保证安全。也就是所说的单例模式,在生成单例对象时使用。

    相关文章

      网友评论

          本文标题:GCD(调度队列任务)

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