谈谈关于GCD相关问题

来源:互联网 发布:基于协同过滤算法 编辑:程序博客网 时间:2024/05/14 08:09

记录下关于学习和使用GCD的一些问题和理解。

GCD,Grand Central Dispatch的简称。首次发布在Mac OS X 10.6 ,iOS 4开始引入使用,是以纯C为底层的强大技术。其操作机制是基于线程上队列对于任务的调度执行,遵循FIFO(First In First Out)。

对于线程常用的三个方式的比较:

 NSThead主要做简单的,缺点是无法管理线程的数量,需要手动管理线程。

// 开启并且执行一个线程+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;// 创建一个线程但是不会执行,需要手动调用- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(id)argument // 通过通知中心监听此消息达到监听线程结束的目的NSThreadWillExitNotification

NSOperation是基于OC的面向对象的多线程可以管理线程数,比GCD多了一些简单实用的功能。

//  maxConcurrentOperationCount设置最大开启的线程数,设置为1,则成为串行队列,否则,为并发队列

GCD是基于C的,效率高,会自动的管理线程周期(包括创建线程,任务处理,销毁线程)。

注意一个技巧:三种线程方式,都可以使用[NSThread currentThread]追踪任务所在的线程。


下面我们主要看下GCD的核心三个方面:线程、 队列 、任务(block执行块)。原理是将一段(Block)代码作为特定任务,放到指定的队列(queue:Serial(串行,同时只能执行一个任务)/globel(并行,同时可执行多个任务,但执行顺序是随机的)/main(全局的Serial,在主线程里面执行任务) dispatch queue)里,进行同步/异步(dispatch_sync/dispatch_async)处理。根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。其中 线程分为:主线程、分线程(子线程)

 队列分为:

(1)串行队列:自己手动创建的,队列中的任务只会顺序执行  (类似排队)(DISPATCH_QUEUE_SERIAL也可使用NULL代替)。

  dispatch_queue_t q = dispatch_queue_create(“....”, DISPATCH_QUEUE_SERIAL);

 (2)并行队列自己手动创建的,队列中的任务通常会并发执行(类似赛跑)

     dispatch_queue_t q = dispatch_queue_create("......", DISPATCH_QUEUE_CONCURRENT);

  ( 3)系统提供的几个并发队列。他们叫做全局调度队列(Global Dispatch Queues) ,一般进程中存在三个全局队列。全局队列有着依次从低到高的四个不同优先级:backgroundlowdefault 以及 high。PS:Apple 的 API 也会使用这些队列,所以你添加的任何任务都不会是这些队列中唯一的任务。

      dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

(4)  主队列,提交至main queue的任务会在主线程中执行,是一个默认的串行队列。

            dispatch_queue_t q = dispatch_get_main_queue();

处理线程中的队列任务,我们需要记得两句话:同步异步(dispatch_sync/dispatch_async)决定开不开线程,串行并行决定开几条线程。

关于我们在实际开发中,利用GCD去做一些线程处理时,常用方法有下面几种简单的使用:

// 异步执行:dispatch_async(dispatch_get_global_queue(0, 0), ^{// something});// 主线程执行:dispatch_async(dispatch_get_main_queue(), ^{// something});// 一次性执行:static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{// code to be executed once});// 延迟2秒执行:double delayInSeconds = 2.0;dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);dispatch_after(popTime, dispatch_get_main_queue(), ^(void){// code to be executed on the main queue after delay});// 自定义dispatch_queue_tdispatch_queue_t  urls_queue = dispatch_queue_create("blog.LL86.com", NULL);dispatch_async(urls_queue, ^{    // your code });dispatch_release(urls_queue);// 快速迭代遍历dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){    // 执行10次代码,index顺序不确定});//常用结构dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{      // 耗时的操作      dispatch_async(dispatch_get_main_queue(), ^{          // 主线程刷新UI      });  });  dispatch_group_t group =  dispatch_group_create();dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    // 执行1个耗时的异步操作});dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    // 执行1个耗时的异步操作});dispatch_group_notify(group, dispatch_get_main_queue(), ^{    // 等前面的异步操作都执行完毕后,回到主线程...});
其中需要注意的是:

dispatch_after  是 延迟提交任务,并不是延迟多少秒后立即执行。在使用GCD做定时源时,使用dispatch_source_create创建一个定时器并绑定到主分派队列上。GCD定时器是基于分派队列,而不是像NSTimer那样基于运行循环,这意味着把他们用在多线程应用中要容易的多。

dispatch_suspend(queue)   挂起队列,并不是立即暂停正在运行的block任务,而是在当前block任务执行结束以后,暂停后续的block运行。\-。-/~

dispatch_sync  都不陌生的是,这句代码本身就是要放入主线程中运行的,因此有时不注意的一些操作会常造成我们常说的死锁现象(也就是线程相互等待现象)。



0 0
原创粉丝点击