平台下并发编程的条研究和实现毕业论文.doc

上传人:sccc 文档编号:4825220 上传时间:2023-05-17 格式:DOC 页数:46 大小:372.52KB
返回 下载 相关 举报
平台下并发编程的条研究和实现毕业论文.doc_第1页
第1页 / 共46页
平台下并发编程的条研究和实现毕业论文.doc_第2页
第2页 / 共46页
平台下并发编程的条研究和实现毕业论文.doc_第3页
第3页 / 共46页
平台下并发编程的条研究和实现毕业论文.doc_第4页
第4页 / 共46页
平台下并发编程的条研究和实现毕业论文.doc_第5页
第5页 / 共46页
点击查看更多>>
资源描述

《平台下并发编程的条研究和实现毕业论文.doc》由会员分享,可在线阅读,更多相关《平台下并发编程的条研究和实现毕业论文.doc(46页珍藏版)》请在三一办公上搜索。

1、毕业论文题 目:iOS平台下并发编程的研究和实现姓 名: 学 号:指导教师(职称): 专 业: 班 级:所 在 学 院: 2015年6月武汉工程大学 毕业论文目 录摘 要 IIIAbstract . V第一章 绪 论 11.1 移动开发中的并发编程 . 11.2 移动操作系统iOS的发展 . 11.3 论文章节安排 . 2第二章 并发程序的设计 .32.1 摒弃线程 . 32.2 异步编程技术介绍 . 42.3 异步编程设计 . 52.4 衡量引入并发后对程序性能的影响 . 62.5 何时使用原生线程 . 6第三章 操作队列73.1 NSOperation 对象简介 . 73.2 子类化 NS

2、Operation . 73.3 自定义操作对象的执行行为 .113.4 开始执行操作对象 .12第四章 调度队列. 154.1 调度队列介绍 .154.2 与队列相关的一些技术点 .164.3 使用block实现任务 .164.4 创建和管理调度队列 .174.5 添加任务到队列中 .204.6 挂起和恢复调度队列 .224.7 使用dispatch信号量控制可用的有限资源.234.8 等待一组任务的完成 .234.9 调度队列和线程安全 .24第五章 调度源. 255.1 Dispatch Source介绍 . 255.2 创建Dispatch Source . 265.3 使用调度源的一

3、些例子 .29总 结 .35致 谢 .37参考文献 .39- 40 -摘 要 移动互联网的浪潮席卷而至,随着智能手机等设备上中央处理器性能的提升,以及多核CPU在移动终端上的普及,每个处理器上的核心只会增加。这种设备性能上的提升使得其应用程序将会更加快捷流畅,程序更加高效以及产品更好的用户体验。在计算机中,单个核心下的并发一般为时间片的轮流,宏观上为多个任务同时执行,微观上每个时刻仍然只执行一个任务。由于多核时代的来临,线程才开始拥有了真正意义上的并行处理。多线程也作为越来越重要的一个部分需要开发者来掌握。然而受限于设备能耗以及内存大小等问题,移动应用开发中的多线程编程又区别于其他程序开发。作

4、为开发者,需要拥抱变化,积极的适应技术的发展,并提升自己。关键词:并发编程;移动互联网;多线程;移动应用开发AbstractWith the advent of mobile Internet, CPU performance boost on Smartphones and other devices, Multi-core CPU on mobile devices became common, the cores of processor will more and more. This performance upgrades of device that make the appli

5、cation will be faster and more smooth, procedures more efficient, and it will have a better user experience. On the computer, concurrent of single core is time turns. Looks at the macro level is performed multiple tasks at the same time, micro level each time still perform only one task. Because of

6、the advent of the multi-core processor, the thread began with a real sense of concurrent processing. Development of multithread increasing importance, and requires the developer to learn. However, due to the limitations of devices energy consumption and memory size, Concurrent programming in mobile

7、application development is different from other programming. As a developer, you need to embrace change, learn the latest techniques, and improve yourself.Keywords:Concurrency Programming;Mobile Internet;Multithreading;Mobile application development第一章 绪 论在移动应用开发中,由于受限与设备屏幕尺寸、处理器性能以及能耗等问题,与传统软件开发有不同

8、之处。从提升程序性能开始,着重介绍如何利用多核处理器进行iOS平台下的多线程开发。1.1移动开发中的并发编程并发所描述的概念就是同时运行多个任务。这些任务在单核 CPU 上所采取的方案为时间片轮流,即同一时间段内执行多核任务,但是同一时刻只有一个任务处于执行状态。在多核 CPU 上才以真正的并行方式来运行。现在大多数智能设备处理器都至少有两个核心,移动操作系统能够并行的运行多个程序,其中大多数的程序运行在后台,并且经常需要一小段 CPU 时间来执行任务。运行在前台的程序与用户交互并且占用大量的 CPU 时间。如果一个程序需要很多任务去执行,但是只能使用处理器中的一部分核心,那么多核的特性将无法

9、发挥,额外的计算资源将被浪费。因此,程序需要充分利用处理器的多核特性,将处理器的性能充分挖掘出来,提高程序的性能以及用户体验。随着移动开发领域的快速发展,对于开发者,需要拥抱变化,尽快掌握移动端的多线程编程技术。1.2移动操作系统iOS的发展在国内外,iOS 系统拥有众多开发者的支持,2014年3月份,AppStore 中的应用数已经超过100万,国内和国外开始进入iOS开发领域的技术人员也再高速增长。OS X 和 iOS 提供了几种不同的 API 来支持并发编程。每一条 API 都具有不同的功能和使用上的一些限制,这就需要在不同的情景下使用最适合的并发方式。同时,这些 API 本身处在不同的

10、抽象层级上。我们很可能会使用它们进行一些特别底层的操作,但同时也意味着将背负起处理好这些操作的责任。为了利用多核,计算机需要软件能够同时干多件事情。现代的多任务操作系统,可以有上百的程序在给定的时间内运行,所以可以调度每个程序执行在不同的核上。然而,大多数的程序属于系统驻守进程,或那些运行在后台,只需要很少 CPU 时间的程序。相反,真正的需要是为单个应用程序高效地使用处理器额外的核心。应用程序利用多核的传统方式是创建多个线程,然而,由于核心的增加,有许多线程相关的问题需要解决,最大的问题是线程代码不能很好的拓展到任意数目的核心。不能创建很多的线程,然后认为程序会很好的运行这些线程。我们无法确

11、认具体使用多少个核心才是最高效的,程序本身也无法很好地通过计算得出这个数值。即使得到了正确的数字,想要这么多线程之间不能干扰且高效运行,仍然具有很大的难度。所以我们需要一种抽象层次比线程高,同时效率又不能比线程太低的方式来处理并发。1.3论文章节安排在过去,在程序中引入并发需要创建额外的一个或多个线程。不幸的是,写线程级别的代码很具有挑战性。线程是很底层的工具,必须手动来管理。对于一个程序,由于线程的最佳数目基于系统负载和底层硬件而动态改变,因此实现一个正确的线程解决方案是非常困难和复杂的。此外,线程的同步机制通常会给软件设计增加复杂性和带来风险,有时候并不能保证一定会提高程序性能。相比较传统

12、的基于线程的系统和应用程序,OS X 和 iOS 更多地采用异步方法来执行并行任务。应用程序只需要定义特定的任务,然后让系统执行它们,而不是直接创建线程。通过让操作系统来管理线程,使得应用程序具有了原生线程不可能具有的可扩展性,同时开发者也有了更加简单高效的编程模式。论文主要介绍了iOS平台下并发编程的技术和技巧,包含以下章节:1. 并行和程序设计:介绍了基本的异步程序设计和异步执行自定义任务的技巧。2. Operation Queues(操作队列):介绍如何使用 Objective-C 对象封装任务并且执行。3. Dispatch Queue(调度队列):在 C 语言编程环境中,如何并行地执

13、行任务。4. Dispatch Sources:如何异步的处理系统事件。第二章 并发程序的设计早期的计算机执行最小任务所需的时间单元取决于CPU的时钟速度,但随着CPU技术的发展以及处理器上的核心越来越密集,散热和其他物理因素开始影响CPU的最大时钟速度。因此厂商们开始将注意力转移到如何在单个芯片上加入更多的处理器核心,即多核CPU,这样单个芯片的性能将又得到提升,因而剩下的问题就是如何充分利用这些增加的核心。传统意义上利用CPU多核特性的方式为创建多个线程,然而移动设备上的CPU受限于系统负载和散热等其他因素,不可以创建大量的线程而又使得程序很好的运行。因此需要一种比较好的方式来解决移动端多

14、线程编程的问题。2.1摒弃线程线程是利用处理器多核特性最直接的方式,也是组成进程的子单元,操作系统的调度器可以对线程进行单独的调度。但是线程无法解决如何弹性地执行多个任务这个很普遍的问题,我们无法控制自己线程中的代码在什么时候开始执行,需要执行多长时间,什么时候暂停。直接使用线程执行任务的另一个问题是,如果线程中的代码使用了框架或库时,那么执行任务所增加的线程总数有可能以指数级别增长。例如,在8核CPU中,创建8个线程完成某个任务,看起来似乎充分利用了CPU的多个核心,但是很有可能每个线程中用到的某个框架又创建了多个线程1。创建每个线程都会消耗一些内存和内核资源,因此如何动态地拓展线程数目就变

15、得尤为重要,我们期望根据系统负载和当前可用的资源能够动态的控制当前活动线程的数量。如果把这项任务交由开发者,那么多线程编程将会变得更加复杂,因此,最好的方式是使用系统为我们提供的并发编程模型。为了不依赖于线程,iOS中采用异步编程的方式来处理需要后台运行的任务。异步这个概念已经存在于计算机中很长时间了,主要用于执行一些需要花费很长时间的任务,例如从磁盘中读取文件,从网络上获取数据等。当异步函数被调用后,任务就会在后台开始执行,同时函数会立刻返回,同时继续执行后续的任务。当处于后台中的任务执行完成后,会发送通知给调用者(通常为函数回调),调用者在函数回调中处理任务完成后的相关操作。这种异步的方式

16、既不影响当前任务的执行,又能利用额外的核心完成非常耗时的操作。在iOS平台下,Apple已经提供了几种异步的编程技术,下面主要介绍这些技术。使用异步编程的技术之一为 GCD(Grand Central Dispatch)。这项技术能够将原本开发者需要编写的线程管理代码转移到系统级别,开发者只需定义需要执行的任务并将其添加到适合的调度队列即可。GCD 负责创建线程并在线程上执行任务所需的代码,现在由于线程管理是系统的一部分,GCD接管了线程管理以及任务的执行,因此这种方式要比传统创建线程的方式高效一些,更重要的是极大地减轻了开发者的负担。另一种使用异步编程的技术为 Operation Queue

17、,它是 Objective-C 对象,如同调度队列一样,开发者只需定义需要执行的任务然后将其添加到操作队列中,操作队列将负责任务的调度和执行。跟 GCD 一样,操作队列处理所有线程管理的工作,并且高效地执行任务代码。2.2异步编程技术介绍下面主要介绍iOS平台中异步编程的几种技术。2.2.1调度队列Dispatch Queue调度队列是一种基于C语言的自定义任务执行机制。调度队列串行或并行地执行任务,任务开始执行的顺序与其添加顺序一致。串行的调度队列同一时间只能执行单个任务,需要等待上个任务完成后才可以开始下个任务的执行。并行的调度队列在同一时间内可以执行多个任务,并不需要等待上个任务完成。调

18、度队列具有以下优点:1. 简洁明了的编程接口。2. 自动全面的线程池管理方案。3. 可提供调度组件的速度。4. 更好的内存利用率(因为线程栈不处于应用程序本身内存区)。5. 任务的异步调用不会导致死锁。6. 竞争条件下拥有更合适的粒度。7. 串行队列提供了更加有效的同步机制。提交到调度队列中的任务必须封装为block对象或者是一个函数,调度队列是GCDGCD和C运行时的一部分。2.2.2调度源Dispatch Sources调度源是用于异步处理特殊系统类型事件的基于C语言的机制。一个调度源封装特殊系统类型事件的相关信息,当发生该事件时,向调度队列提交函数或特殊的block对象。简单来说,调度源

19、是一个监视某些类型事件的对象。当这些事件发生时,它自动将一个block对象放入一个调度队列的执行例程中。可以使用调度源来监听以下系统事件:计时器、信号处理描述符相关的进程事件、Mach 端口事件和自定义的触发事件2。2.2.3操作队列Operation Queues操作队列由iOS中NSOperationQueue类实现。相比较调度队列按照添加顺序执行任务,操作队列在决定任务执行顺序时还会考虑其他一系列因素。提交到操作队列的对象必须是NSOperation类的子类,NSOperation子类的对象封装执行的任务以及所需的数据。2.3异步编程设计在考虑将现有的代码重新设计以支持并发时,首先应该确

20、认是否有这个必要。一般来说,并发将大多数耗时任务放至其他工作线程执行,可以使得主线程空闲。由于iOS中有关UI部分的事件都在主线程中处理,因此空闲的主线程能够更加有效地处理相应用户事件,使得界面更加流畅,提升用户体验,同时还能利用多核特性做更多的工作。当然,引入并发也会增加开销和代码量,增加编码和Debug难度。由于增加了软件设计的复杂性,并发并不是产品开发周期快结束时需要加入的一个功能点。每一个程序都有不同的需求和指导任务,可以大概通过以下几点来确认是否应该引入并发。2.3.1明确应用程序预期的行为在考虑程序中引入并发前,首先应该从明确程序正确的行为开始。了解程序预期的行为,在之后的设计中可

21、以帮助验证设计的可行性。第一件事,就是罗列出程序所有要做的任务以及相关的数据结构。一开始,可能会从用户的点击事件任务开始,因为用户点击事件提供了很清晰的需求,用户点击了哪里,期望得到什么样的行为。实际中更应该罗列其他无需用户交互的应用程序任务,比如基于计时器的任务。当整理出较高级别任务的列表后,将任务再分解为完成所需的一系列步骤,在这个阶段,应该是主要是对数据或者对象做一些修改,以及了解这些修改如何影响程序的整体状态。还应该注意对象和数据结构之间的依赖关系,注意对一个对象的修改是否影响其他对象。2.3.2分解出任务的执行单元在罗列程序任务时,应该基本明确哪些任务并发处理时会高效一些。如果整个任

22、务中更改了某些步骤的执行顺序,任务执行结果会改变,那么可能需要考虑串行执行这些步骤。如果任务的执行结果与任务中步骤的执行顺序无关,那么可以使用并发来提高性能。这种情况下,将任务拆分出一步一步执行的单元,然后将它们封装成block或者Operation对象并分发到对应的队列。在确定任务中的每个执行单元时,一开始不需要过多的担心工作量是不是太大。即使开启线程需要一定的开销,但是调度队列和操作队列的一个优点就是在多数情况下仍比传统使用线程的方式开销要小的多。所以,在使用队列执行一些很小的工作单元时,效率是高于使用线程的。当然,仍需要通过衡量实际运行时的效率来调整任务的大小,但是在一开始,没必要考虑任

23、务单元是不是拆分得太小了。2.3.3决定需要分发任务的队列现在已经将任务拆分为工作单元,并且用block或者NSOperation对象封装起来了。如果使用block封装任务,可以向一个串行或并行的队列添加block来执行。如果对于执行顺序有特殊的要求,应该使用串行的队列。如果工作单元对于执行顺序没有要求,可以使用并发的队列或者多个不同的并发队列,具体取决于程序需求。如果使用NSOperation对象,那么配置对象将比选择队列更加重要。想要串行地执行NSOperation对象,必须要先处理这些对象之间的依赖关系。依赖项会阻止当前操作继续执行,直到所依赖的对象完成它们的工作。2.4衡量引入并发后对

24、程序性能的影响调度队列、操作队列和调度源都提供了简单的并发编程方式。然而这些技术并不能保证一定能够提高程序的性能或改善代码的执行效率。因此仍然需要以一种合理的方式去使用并发,且不能过度的使用操作系统资源。在代码中引用并发之前,无论是使用队列还是线程,都应该采集一些基准的性能指标反映当前的程序性能。当使用并发后,采集并发后的性能指标与之前的基准进行比较,看并发的引入是否提高了程序性能,推荐使用性能测试工具来检测。2.5何时使用原生线程虽然操作队列和调度队列是执行并发的首选方式,但这并不是适用于任何情况的。根据应用程序任务需求的不同,有时候可能仍需创建自定义的线程。如果的确有这个需要,那么尽可能使

25、用更少的线程,尽量不要使用线程做其他的操作。线程仍然是实现代码运行在确定时间的最佳方式,调度队列尽管会尽可能快速地执行任务,但是仍然不能解决真实时间约束。如果需要了解更多线程运行在后台的预计行为,线程通常会提供更好的选择。不过,使用线程时最好再次确认其必要性。第三章 操作队列在iOS平台中,Cocoa 框架中的 NSOperation 通过面向对象的方式封装了执行异步操作的工作,主要用于 Operation Queue。本章节主要介绍 NSOperation 类的使用以及自定义子类化。3.1NSOperation对象简介Operation对象是NSOperation类的实例,用来封装程序中需要

26、异步执行的一些操作。NSOperation是抽象基类,所以不能直接使用,需要通过继承实现自己的子类来执行任务。由于基类本身已经实现了一些基本操作,所以可以很方便地继承它。除此之外,Cocoa 框架还提供了两个已经定义好的子类,用于一些常用的异步操作,可以在代码中直接使用它们3。第一个子类为NSInvocationOperation,基于一个方法选择子和对象创建的对象,当程序中已经存在现有的方法,并且希望异步执行时,是一个较好的选择。第二个子类为NSBlockOperation,可以使用这个类并发地执行一个或多个block对象。当所有相关的block执行完毕后,operation对象才完成。当上

27、面提供的两个类不能满足需求时,可以考虑定义自己的NSOperation子类。这样可以获得更多有关操作对象的控制权,通常用于一些比较复杂的操作。所有的操作对象都支持以下重要的功能:1.支持操作对象间建立基于图论的依赖关系,这些依赖项会阻止当前对象的运行,直到对象所依赖的其他项都完成。2.支持一个可选的completion block,当操作对象的主任务完成时调用。3.支持监听操作对象状态的改变,需要操作对象使用 KVO。4.支持优先级,会影响操作对象的执行顺序。5.支持取消操作对象的执行,正在执行时也可以取消。操作对象旨在提高程序的并发性,同时也是一种很好的封装应用程序行为的方式。应该提交操作对

28、象到操作队列上,让它们在单独的线程或者多个线程上执行相应的工作,而不是在主线程上做大量的操作。3.2子类化NSOperation NSOperation类为所有的操作对象提供了一些基本的子类化点。同时提供了大量的基础方法用于实现KVO依赖,然而,有时候仍需补充现有的基础结构,来确保业务的正常运行。其他一些额外的工作量取决于是否实现并发操作。定义非并发的操作要比并发简单的多,对于非并发的操作,只需要执行主要任务并实现取消方法。对于并发操作,必须重载现有的一些代码,下面各节主要讲述重载的内容。3.2.1执行主任务每个操作对象至少需要实现初始化和主任务这两个方法,通过这两个方法,操作对象可以实例化并

29、且得到一个需要执行的任务。代码示例如下:interface CWNonConcurrentOperation : NSOperationproperty id (strong) data;-(id)initWithData:(id)data;endimplementation CWNonConcurrentOperation- (id)initWithData:(id)data if (self = super init) myData = data; return self;/ 主任务-(void)main try / 根据当前操作对象的数据进行处理,得出结果 catch(.) / 不要在这

30、里抛出异常 end3.2.2实现取消操作当操作对象开始执行后,只有显示地取消时,才会真正结束执行。取消操作可以发生在任何时间,甚至在操作对象还未开始执行时。尽管NSOperation抽象基类已经提供了取消操作,但是应该在子类中重载它,并在取消操作中释放已经占有的资源。操作对象应该在整个执行周期中检查是否有取消事件发生,并且优雅地处理该事件。支持取消需要做的就是在代码中周期性的调用操作对象的 isCancelled 方法,并且当不返回YES时立刻返回。支持取消操作是很重要的,isCancelled方法调用返回非常快,因此可以频繁的调用而不会造成额外的开销。可能需要在以下地方调用isCancell

31、ed方法:1. 在执行任何自然操作时立刻调用。2. 在循环中至少调用一次,或者当循环耗时较长时调用多次。3. 任何可能中断操作的地方。3.2.3配置操作对象使其并发执行默认情况下操作队列以同步方式执行,也就是说它们在调用start方法的线程上执行任务。操作队列为非并发的任务提供了线程,不过现在大多数操作需要异步运行,因此需要重载一些方法。下面列出了并发执行时需要重载的方法:start :(必须)所有的并发操作必须重载这个方法,实现自定义的行为。通过调用start方法手动执行操作。因此,这个方法的实现是操作开始执行的起点,并且是设置线程或者其他运行环境的地方。需要注意的是任何时候都不能调用sup

32、er。main:(可选)这个方法通常用于实现操作对象相应的任务。尽管可以在start方法中实现这些任务,但是将其转移到这里会有较好的代码结构,使得操作对象的准备工作和执行阶段分开。isExecuting、isFinished:(必须)并发操作应该建立运行环境并且报告状态给外面的用户,然而,一个并发操作必须维护一些状态信息,来了解何时开启任务,何时完成任务。这些方法的实现必须是线程安全的,可能与KVO有关4。isConcurrent:重载并且返回YES即可。下面的代码示例简单的实现了如何子类化一个并发的操作对象:/ 子类化 NSOperationinterface MyOperation: NS

33、Operation BOOL executing;BOOL finished;- (void)completeOperation;endimplementation MyOperation/ 实现初始化方法- (id)init self = super init;if (self) executing = NO;finished = NO;return self;/ 重载操作对象的并发性属性- (BOOL)isConcurrent return YES;/ 重载实现 KVO- (BOOL)isExecuting return executing;- (BOOL)isFinished retur

34、n finished;下面的代码示例为如何在start方法中做准备工作,以及实现KVO:- (void)start / 周期性的检查是否有取消操作发生if (self isCancelled) / 如果当前操作对象被取消,那么需要改变finished状态信息self willChangeValueForKey:”isFinished”;finished = YES;self didChangeValueForKey:”isFinished”;/ 当取消操作发生时,需要直接返回return;/ 当操作对象没有被取消时,开始执行任务self willChangeValueForKey:”isExe

35、cuting”;/ 开启单独的线程并执行任务NSThread detachNewThreadSelector:selector(main) toTarget:self withObject:nil;/ 这个时候任务已经开始了,需要改变executing状态executing = YES;self didChangeValueForKey:”isExecuting”;当编写完操作对象的准备阶段的start方法后,就可以开始编写main方法,将start方法和main方法分开使得代码有清晰的结构,有助于调试和Debug。在main方法中,当操作对象的状态改变时,仍需实现对象的KVO规则,如下:-

36、(void)main try / 开始执行有关操作的主任务/ 执行完成后调用完成操作self completeOperation;catch() / 仍然无需抛出异常- (void)completeOperation self willChangeValueForKey:”isFinished”;self willChangeValueForKey:”isExecuting”;/ 在任务完成后,需要更改对应的状态信息executing = NO;finished = YES;self didChangeValueForKey:” isFinished”;self didChangeValueF

37、orKey:” isExecuting”;3.2.4保证KVO规则NSOperation 对于以下属性实现 KVO:isCancelled、isConcurrent、isExecuting、isFinished、isReady、dependencies、queuePriority、completionBlock。如果对NSOperation重写了start方法或者做了其他一些重大的定制,除了重载main方法,还需要确保自定义对象仍然保证了KVO规则。如果想要实现对其他操作对象依赖项的支持,可以重载isReady方法,直到自定义的依赖项已经满足,不然一直返回NO(这里应该调用super),当状态

38、改变时,通过发出KVO通知告知状态的改变。除非你重写 addDependency 或 removeDependency 方法,不然无需操心dependencies的KVO规则5。尽管可以生成其他key的 KVO,但是最好不要这样做。如果需要取消操作对象,只需调用其cancel方法即可,同样,整个过程可能不需要修改队列优先级。最后,除非操作对象会动态改变isConcurrent属性,不然无需实现其KVO规则。3.3自定义操作对象的执行行为成功建操作对象后,在将其添加到队列之前,可以对操作对象进行配置。这一节中所描述的配置类型既可以应用于自定义的继承于NSOperation类的子类,也可应用于系统

39、提供的子类。3.3.1配置操作对象之间的依赖关系依赖关系是一种序列化不同操作对象的方式。一个对象依赖于其他对象的执行状态,只有当其依赖的对象全部完成时,它自己才可以开始执行。因此,可以使用依赖关系来创立复杂的执行顺序。使用NSOperation类的addDependency:方法创建两个对象之间的依赖关系。这个方法创建一个从当前对象到目标对象单向的依赖关系,其返回结果可以作为一个参数来传递。这种依赖性表示当前的对象只有在目标对象完成时才可以开始执行。这种依赖关系并不局限于同一个队列中的操作对象,因为操作对象本身管理自己的依赖项,所以,完全可以在不同队列中的不同操作对象之间创建依赖关系。需要注意

40、的是,不要产生循环依赖的关系。当所有的依赖项都已经完成时,当前操作对象将准备开始执行(当重载isReady方法后,这个状态需要使用自己创建的标准)。如果对象已经处于队列中,那么队列可能随时开始执行这个对象,如果是手动管理对象的执行,那么需要调用操作对象的start方法。应该总是在操作对象运行之前或者添加到队列之前配置它的依赖关系,在运行之后添加依赖关系可能会无效。依赖关系依赖于每个对象当状态变化时发送KVO通知,当自定义对象的这种行为时,为了避免出错,可能需要在代码中生成对应的KVO通知。3.3.2更改操作执行的优先级对于添加到队列的操作对象,执行顺序首先取决于已经入队操作对象的准备情况,然后

41、取决于其优先级。准备情况取决于操作对象依赖的其他对象,但是优先级是操作对象自身的属性,默认情况下,所有新创建的操作对象都有一个默认的优先级,但可以通过setQueuePriority方法增大或者减小优先级。优先级只适用于同一个队列中的不同对象,如果程序中有多个操作队列,每个对象在不同的队列中的优先级是相互独立的。因此,低优先级的操作对象可能在不同的队列中执行得比高优先级的操作对象要早。优先级不是依赖关系的替代,优先级只影响某个队列中已经做好执行准备的操作对象,举个例子,如果一个队列中,存在已经准备好的两个不同优先级的对象,那么首先执行高优先级的,但如果高优先级的还未准备好,低优先级的已经准备好

42、了,那么首先会执行低优先级的,如果想要使某个操作对象必须在另一个操作对象执行完毕之后才执行,那么应该使用依赖关系而不是优先级。3.4开始执行操作对象当操作对象初始化并且配置完成后,需要执行它们来完成程序中的工作。3.4.1更改操作执行的优先级到目前为止,执行操作对象最简单的方式就是将其添加到一个操作队列,应用程序本身负责创建和维护需要使用的操作队列。程序可以拥有多个操作队列,但如果太多会有限制。操作队列与系统根据内核和系统负载,决定某一时刻维持多少并发的数量,因此,创建太多的操作队列不一定能够立即执行其中的操作对象。创建队列与创建其他对象的方式一样。可以使用addOperation:方法添加操

43、作对象,同时还可以使用 addOperationWithBlock:方法添加block,所有这些方法均进队一个操作对象并开始执行。大多数情况下,操作对象会在添加到队列后就开始执行,但是仍然还有其他一些原因可能会导致操作对象被推迟执行。例如某个操作对象依赖于其他操作对象的完成,或者操作队列本身是被挂起的,亦或是操作数超过了队列设置的最大并发数。一定要注意当操作对象添加到操作队列后,不能去改变它,你可以使用NSOperation类的其他方法来查看它当前的状态。尽管操作队列是并发的,但是仍然可以通过设置其最大并发数为1使其强制串行执行,尽管同一时间只有一个操作对象执行,但是其执行顺序仍然受其他因素的影响,因此串行的操作队列并不能提供像GCD一样的行为,如果串行队列中操作对象之间的执行顺序很重要,那么使用依赖关系仍然是最适合的方式。3.4.2手动实行操作对象尽管操作队列可以很方便地执行操作对象,但是有时候仍希望不通过操作队列来执行某些操作对象,下面是一些手动执行需要注意的地方,最重要的是必须要保证其准备好执行然后调用其start方法。操作对象不会在isReady方法返回YES之前执行,isReady方法取决于其依赖的对象是否全部执行完毕。手动执行时必须显示调用其start方法,不能使用ma

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/施工/环境 > 农业报告


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号