GCD简介一:基本概念和Dispatch Queue

一、什么是GCD?

Grand Central Dispatch或者GCD,是一套低层API,提供了一种新的方法来进行并发程序编写。从基本功能上讲,GCD有点像NSOperationQueue,他们都允许程序将任务切分为多个单一任务然后提交至工作队列来并发地或者串行地执行。GCD比之NSOpertionQueue更底层更高效,并且它不是Cocoa框架的一部分。

除了代码的平行执行能力,GCD还提供高度集成的事件控制系统。可以设置句柄来响应文件描述符、mach ports(Mach port 用于 OS X上的进程间通讯)、进程、计时器、信号、用户生成事件。这些句柄通过GCD来并发执行。

GCD的API很大程度上基于block,当然,GCD也可以脱离block来使用,比如使用传统c机制提供函数指针和上下文指针。实践证明,当配合block使用时,GCD非常简单易用且能发挥其最大能力。
你可以在Mac上敲命令“man dispatch”来获取GCD的文档。

二、优势:GCD提供很多超越传统多线程编程的优势:

易用: GCD比之thread跟简单易用。由于GCD基于work unit而非像thread那样基于运算,所以GCD可以控制诸如等待任务结束、监视文件描述符、周期执行代码以及工作挂起等任务。基于block的血统导致它能极为简单得在不同代码作用域之间传递上下文。

效率: GCD被实现得如此轻量和优雅,使得它在很多地方比之专门创建消耗资源的线程更实用且快速。这关系到易用性:导致GCD易用的原因有一部分在于你可以不用担心太多的效率问题而仅仅使用它就行了。

性能: GCD自动根据系统负载来增减线程数量,这就减少了上下午切换以及增加了计算效率。

三、Dispatch Objects

尽管GCD是纯c语言的,但它被组建成面向对象的风格。GCD对象被称为dispatch object。Dispatch object像Cocoa对象一样是引用计数的。使用dispatch_release和dispatch_retain函数来操作dispatch object的引用计数来进行内存管理。但主意不像Cocoa对象,dispatch object并不参与垃圾回收系统,所以即使开启了GC,你也必须手动管理GCD对象的内存。

Dispatch queues 和 dispatch sources(后面会介绍到)可以被挂起和恢复,可以有一个相关联的任意上下文指针,可以有一个相关联的任务完成触发函数。可以查阅“man dispatch_object”来获取这些功能的更多信息。

四、Dispatch Queues

GCD的基本概念就是dispatch queue。dispatch queue是一个对象,它可以接受任务,并将任务以先到先执行的顺序来执行。dispatch queue可以是并发的或串行的。并发任务会像NSOperationQueue那样基于系统负载来合适地并发进行,串行队列同一时间只执行单一任务。

GCD中有三种队列类型:
(1)The main queue: 与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。
(2)Global queues: 全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。
(3)用户队列: 用户队列 (GCD并不这样称呼这种队列, 但是没有一个特定的名字来形容这种队列,所以我们称其为用户队列) 是用函数 dispatch_queue_create 创建的队列. 这些队列是串行的。正因为如此,它们可以用来完成同步机制, 有点像传统线程中的mutex。

五、创建队列

要使用用户队列,我们首先得创建一个。调用函数dispatch_queue_create就行了。函数的第一个参数是一个标签,这纯是为了debug。Apple建议我们使用倒置域名来命名队列,比如“com.dreamingwish.subsystem.task”。这些名字会在崩溃日志中被显示出来,也可以被调试器调用,这在调试中会很有用。第二个参数目前还不支持,传入NULL就行了。

六、提交 Job

向一个队列提交Job很简单:调用dispatch_async函数,传入一个队列和一个block。队列会在轮到这个block执行时执行这个block的代码。下面的例子是一个在后台执行一个巨长的任务:
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
             [self goDoSomethingLongAndInvolved];
             NSLog(@"Done doing something long and involved");
     });
dispatch_async 函数会立即返回, block会在后台异步执行。 

当然,通常,任务完成时简单地NSLog个消息不是个事儿。在典型的Cocoa程序中,你很有可能希望在任务完成时更新界面,这就意味着需要在主线程中执行一些代码。你可以简单地完成这个任务——使用嵌套的dispatch,在外层中执行后台任务,在内层中将任务dispatch到main queue:
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
             [self goDoSomethingLongAndInvolved];
             dispatch_async(dispatch_get_main_queue(), ^{
                   [textField setStringValue:@"Done doing something long and involved"];
             });
     });

还有一个函数叫dispatch_sync,它干的事儿和dispatch_async相同,但是它会等待block中的代码执行完成并返回。结合 __block类型修饰符,可以用来从执行中的block获取一个值。例如,你可能有一段代码在后台执行,而它需要从界面控制层获取一个值。那么你可以使用dispatch_sync简单办到:
     __block NSString *stringValue;
     dispatch_sync(dispatch_get_main_queue(), ^{
             // __block variables aren't automatically retained
             // so we'd better make sure we have a reference we can keep
             stringValue = [[textField stringValue] copy];
     });
     [stringValue autorelease];
     // use stringValue in the background now

我们还可以使用更好的方法来完成这件事——使用更“异步”的风格。不同于取界面层的值时要阻塞后台线程,你可以使用嵌套的block来中止后台线程,然后从主线程中获取值,然后再将后期处理提交至后台线程:
     dispatch_queue_t bgQueue = myQueue;
         dispatch_async(dispatch_get_main_queue(), ^{
             NSString *stringValue = [[[textField stringValue] copy] autorelease];
  `          dispatch_async(bgQueue, ^{
                 // use stringValue in the background now
             });
     });
取决于你的需求,myQueue可以是用户队列也可以使全局队列。
 
七、不再使用锁(Lock)

用户队列可以用于替代锁来完成同步机制。
在传统多线程编程中,你可能有一个对象要被多个线程使用,你需要一个锁来保护这个对象:NSLock *lock; 访问代码会像这样:
     - (id)something
     {
         id localSomething;
         [lock lock];
         localSomething = [[something retain] autorelease];
         [lock unlock];
         return localSomething;
     }
 
     - (void)setSomething:(id)newSomething
     {
         [lock lock];
         if(newSomething != something)
         {
             [something release];
             something = [newSomething retain];
             [self updateSomethingCaches];
         }
         [lock unlock];
     }

使用GCD,可以使用queue来替代:dispatch_queue_t queue;
要用于同步机制,queue必须是一个用户队列,而非全局队列,所以使用usingdispatch_queue_create初始化一个。然后可以用dispatch_async 或者 dispatch_sync将共享数据的访问代码封装起来:
     - (id)something
     {
         __block id localSomething;
         dispatch_sync(queue, ^{
             localSomething = [something retain];
         });
         return [localSomething autorelease];
     }
 
     - (void)setSomething:(id)newSomething
     {
         dispatch_async(queue, ^{
             if(newSomething != something)
             {
                 [something release];
                 something = [newSomething retain];
                 [self updateSomethingCaches];
             }
         });
     }
值得注意的是dispatch queue是非常轻量级的,所以你可以大用特用,就像你以前使用lock一样。

八、现在你可能要问:“这样很好,但是有意思吗?我就是换了点代码办到了同一件事儿。”
实际上,使用GCD途径有几个好处:

平行计算: 注意在第二个版本的代码中, -setSomething:是怎么使用dispatch_async的。调用 -setSomething:会立即返回,然后这一大堆工作会在后台执行。如果updateSomethingCaches是一个很费时费力的任务,且调用者将要进行一项处理器高负荷任务,那么这样做会很棒。

安全: 使用GCD,我们就不可能意外写出具有不成对Lock的代码。在常规Lock代码中,我们很可能在解锁之前让代码返回了。使用GCD,队列通常持续运行,你必将归还控制权。

控制: 使用GCD我们可以挂起和恢复dispatch queue,而这是基于锁的方法所不能实现的。我们还可以将一个用户队列指向另一个dspatch queue,使得这个用户队列继承那个dispatch queue的属性。使用这种方法,队列的优先级可以被调整——通过将该队列指向一个不同的全局队列,若有必要的话,这个队列甚至可以被用来在主线程上执行代码。

集成: GCD的事件系统与dispatch queue相集成。对象需要使用的任何事件或者计时器都可以从该对象的队列中指向,使得这些句柄可以自动在该队列上执行,从而使得句柄可以与对象自动同步。

转载自:http://www.dreamingwish.com/dream-2012/of-of-of-of-gcd-introduced-1-basic-concepts-in-and-the-dispatch-queue.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/500140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大学生计算机二级大集报名最好,在校大学生如何报名计算机二级?

2009-12-05 回答首先要根据你的所学专业来衡量自己考哪项计算级二级有c语言, vb, vf, java, access, c 六项可选考其中一个你会的 考下来能拿计算机二级了考试分两部分,上机和笔试。笔试就是一些基本的操作…

GCD简介二:多核心的性能

一、概念为了在单一进程中充分发挥多核的优势,我们有必要使用多线程技术。在低层,GCD全局dispatch queue仅仅是工作线程池的抽象。这些队列中的Block一旦可用,就会被dispatch到工作线程中。提交至用户队列的Block最终也会通过全局队列进入相同…

怪哉翻译软件测试,[东方朔传翻译]东方朔传·怪哉原文与翻译

东方朔传怪哉原文与翻译原文:《太平广记》卷四七三引《东方朔传》汉武帝幸⑦甘泉,驰道中有虫,赤色,头牙齿耳鼻尽具,观者莫识①。帝乃使东方朔视之,还对②曰:“此虫名怪哉。昔时拘系⑧无辜&#…

GCD简介三:Dispatch Sources

一、何为Dispatch Sources简单来说,dispatch source是一个监视某些类型事件的对象。当这些事件发生时,它自动将一个block放入一个dispatch queue的执行例程中。我们到底讨论哪些事件类型?下面是GCD 10.6.0版本支持的事件:Mach por…

GCD简介四:挂起,目标指定,信号量

一、Dispatch Queue挂起dispatch queue可以被挂起和恢复。使用 dispatch_suspend函数来挂起,使用 dispatch_resume 函数来恢复。这两个函数的行为是如你所愿的。另外,这两个还是也可以用于dispatch source。一个要注意的地方是,dispatch que…

如何自己做网站发布到服务器上面,怎么做网站 四步教你搭建自己的网站

1、购买域名如果想要做一个自己的网站,购买一个自己喜欢的域名就是首先要做的!当你购买好自己的域名,就走出了搭建自己网站的第一步!2、购买空间/主机/服务器空间/主机/服务器,看着好像很复杂,其实很简单&a…

GCD简介五:补充

1.GCD在iOS4.0及以上可用。2.GCD中,主线程队列是串行的;全局队列是并行的,并由整个进程共享;用户自建队列,在iOS4.3以下,只能是串行,iOS4.3及以上,可以是并行的。3.dispatch_suspend…

ajax delete 传递参数,springMVC使用PUT、DELETE方法传递参数解决方案

在web.xml中新增过滤器HiddenHttpMethodFilterorg.springframework.web.filter.HiddenHttpMethodFilterHiddenHttpMethodFilter/*需要注意的是,只有context-type:application/x-www-form-urlencoded的请求才会被过滤。该过滤器的核心方法如下&#xff1a…

ARC简介

1、简介:ARC(Automatic Reference Counting),自动引用计数,需要XCode4.2和SDK5.0的支持。它是一个在编译期间工作的技术,编译器在编译的时候会根据变量的作用域为objective-c变量添加合适的retain、release、autorelease等函数。原…

微信验证码无法连接到服务器,微信无法连接到服务器1237解决方法

太多朋友在使用微信过程中出现微信无法连接到服务器1237的问题,出现这个问题的原因有很多种,接下来小编带大家找出问题原因,然后成功解决这个问题。以下是网友们成功解决此问题的方法,大家可以参考一下方法一:首先重启…

iOS后台任务

一、概览1.从iOS4.0开始,系统添加了多任务特征,允许应用在按下Home键之后,继续执行后台任务。大部分应用在进入后台之后就进入了挂起状态,只有那些为用户提供重要服务的App能够在进入后台之后继续运行一段时间。2.一般情况下&…

王者荣耀服务器维护bug,8月23日王者荣耀ios版更新一直显示维护是什么情况?更新出现bug 附处理方法...

相信很多喜爱玩王者荣耀的游戏玩家可以知道今天是王者荣耀星计划更新的日子,但是有很多苹果手机的小伙伴出现了一个问题,那就是无法进入游戏,甚至是更新十分的缓慢,在这里本文为您带来最新的解决方法!苹果手机微信区一…

服务器任务栏不显示程序,Win10任务栏不显示应用程序标签怎么办?

Win10任务栏不显示应用程序标签怎么办?执拗的人才会一条路走到黑,多个朋友多条路,多个方法多种选择。关于Win10任务栏不显示应用程序标签,一般是explorer进程出现故障导致,哦!忘记说了Win10系统下这东东改了个好听的名字&#xf…

Objective-C复制解析

一、为什么使用复制?1.C语言以及Objective-C语言总是按值传递的,按值传递意味着是隐式复制。在这里就分为两种情况:(1)如果是非对象类型,对传递过来的值进行更改,只会更改副本,对原始值没有影响&#xff0c…

udp协议的服务器是哪种类型,UDP协议

UDP协议1.UDP使用场景域名系统若是执行时间内,没有响应返回,证明包已丢失。音频或视频数据包的丢失只会造成通话或视频的干扰和不清楚,而不会像TCP协议那样造成通话的丢失或卡顿。2.UDP和TCP的类比UDP类似于邮局,数据的接受与否和…

归档和解档-Archiver

一、概念1.归档用于保存对象,包括被归档对象之间的各种相互关系或者依赖性。解档用于重建以前归档的对象与关系。在其它面向对象的语言中,一般使用术语"序列化"来描述归档解档模式。2.归档的对象通常存储为二进制数据,可以在内存或…

碧雪情天服务器地址源如何修改,稀有游戏《碧雪情天online》网络版王者归来一键服务端+客户端 支持转生系统和新图...

碧雪情天online王者归来版本介绍:1.增加新的职业套装;2.增加高川台、雪域、魔灵和天庭等新图;3.仙侠岭先知处添加角色转生功能;4.碣石村宝官添加装备签名和祝福卡兑换角色经验功能;5.增加宠物经验兑换角色经验功能;6.其它新内容和…

Objective-C单例

一、要点:1.当在应用程序中只需要有类的一个实例,并且可以被其它对象轻松的访问的时候,可以使用单例类。2.首先需要声明一个静态的类的实例变量,并初始化为nil。应该将该实例变量声明在类的实现文件中,表示变量仅在该实…

刚买的ubuntu服务器 为什么没有文件,新买的linux服务器怎么使用

新买的linux服务器怎么使用 内容精选换一换切换操作系统是为您的弹性云服务器重新切换一个系统盘。切换完成后弹性云服务器的系统盘ID会发生改变,并删除原有系统盘。如果弹性云服务器当前使用的操作系统不能满足业务需求(如软件要求的操作系统版本较高),…

iOS应用横竖屏切换

一、概述: 在iOS应用中,由UIViewController来控制屏幕翻转,根据需要随设备方向自动切换。在iOS6和之前的系统之间,控制方法发生了些变化。二、视图伸缩属性:1.UIView类的autoresizingMask属性,用来指定当它…