GCD(调度队列任务)

2016-07-13  本文已影响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 函数可以使得在多线程环境下执行,也可以保证安全。也就是所说的单例模式,在生成单例对象时使用。

上一篇下一篇

猜你喜欢

热点阅读