iOS平臺下并發(fā)編程的研究和實現(xiàn)畢業(yè)論文_第1頁
iOS平臺下并發(fā)編程的研究和實現(xiàn)畢業(yè)論文_第2頁
iOS平臺下并發(fā)編程的研究和實現(xiàn)畢業(yè)論文_第3頁
iOS平臺下并發(fā)編程的研究和實現(xiàn)畢業(yè)論文_第4頁
iOS平臺下并發(fā)編程的研究和實現(xiàn)畢業(yè)論文_第5頁
已閱讀5頁,還剩41頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、畢業(yè)論文題 目:ios平臺下并發(fā)編程的研究和實現(xiàn)姓 名: 學 號:指導教師(職稱): 專 業(yè): 班 級:所 在 學 院: 2015年6月武漢工程大學 畢業(yè)論文目 錄摘 要 iiiabstract . v第一章 緒 論 11.1 移動開發(fā)中的并發(fā)編程 . 11.2 移動操作系統(tǒng)ios的發(fā)展 . 11.3 論文章節(jié)安排 . 2第二章 并發(fā)程序的設計 .32.1 摒棄線程 . 32.2 異步編程技術介紹 . 42.3 異步編程設計 . 52.4 衡量引入并發(fā)后對程序性能的影響 . 62.5 何時使用原生線程 . 6第三章 操作隊列73.1 nsoperation 對象簡介 . 73.2 子類化 ns

2、operation . 73.3 自定義操作對象的執(zhí)行行為 .113.4 開始執(zhí)行操作對象 .12第四章 調度隊列. 154.1 調度隊列介紹 .154.2 與隊列相關的一些技術點 .164.3 使用block實現(xiàn)任務 .164.4 創(chuàng)建和管理調度隊列 .174.5 添加任務到隊列中 .204.6 掛起和恢復調度隊列 .224.7 使用dispatch信號量控制可用的有限資源.234.8 等待一組任務的完成 .234.9 調度隊列和線程安全 .24第五章 調度源. 255.1 dispatch source介紹 . 255.2 創(chuàng)建dispatch source . 265.3 使用調度源的一

3、些例子 .29總 結 .35致 謝 .37參考文獻 .39- 40 -摘 要 移動互聯(lián)網(wǎng)的浪潮席卷而至,隨著智能手機等設備上中央處理器性能的提升,以及多核cpu在移動終端上的普及,每個處理器上的核心只會增加。這種設備性能上的提升使得其應用程序將會更加快捷流暢,程序更加高效以及產(chǎn)品更好的用戶體驗。在計算機中,單個核心下的并發(fā)一般為時間片的輪流,宏觀上為多個任務同時執(zhí)行,微觀上每個時刻仍然只執(zhí)行一個任務。由于多核時代的來臨,線程才開始擁有了真正意義上的并行處理。多線程也作為越來越重要的一個部分需要開發(fā)者來掌握。然而受限于設備能耗以及內存大小等問題,移動應用開發(fā)中的多線程編程又區(qū)別于其他程序開發(fā)。作

4、為開發(fā)者,需要擁抱變化,積極的適應技術的發(fā)展,并提升自己。關鍵詞:并發(fā)編程;移動互聯(lián)網(wǎng);多線程;移動應用開發(fā)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第一章 緒 論在移動應用開發(fā)中,由于受限與設備屏幕尺寸、處理器性能以及能耗等問題,與傳統(tǒng)軟件開發(fā)有不同

8、之處。從提升程序性能開始,著重介紹如何利用多核處理器進行ios平臺下的多線程開發(fā)。1.1移動開發(fā)中的并發(fā)編程并發(fā)所描述的概念就是同時運行多個任務。這些任務在單核 cpu 上所采取的方案為時間片輪流,即同一時間段內執(zhí)行多核任務,但是同一時刻只有一個任務處于執(zhí)行狀態(tài)。在多核 cpu 上才以真正的并行方式來運行。現(xiàn)在大多數(shù)智能設備處理器都至少有兩個核心,移動操作系統(tǒng)能夠并行的運行多個程序,其中大多數(shù)的程序運行在后臺,并且經(jīng)常需要一小段 cpu 時間來執(zhí)行任務。運行在前臺的程序與用戶交互并且占用大量的 cpu 時間。如果一個程序需要很多任務去執(zhí)行,但是只能使用處理器中的一部分核心,那么多核的特性將無法

9、發(fā)揮,額外的計算資源將被浪費。因此,程序需要充分利用處理器的多核特性,將處理器的性能充分挖掘出來,提高程序的性能以及用戶體驗。隨著移動開發(fā)領域的快速發(fā)展,對于開發(fā)者,需要擁抱變化,盡快掌握移動端的多線程編程技術。1.2移動操作系統(tǒng)ios的發(fā)展在國內外,ios 系統(tǒng)擁有眾多開發(fā)者的支持,2014年3月份,appstore 中的應用數(shù)已經(jīng)超過100萬,國內和國外開始進入ios開發(fā)領域的技術人員也再高速增長。os x 和 ios 提供了幾種不同的 api 來支持并發(fā)編程。每一條 api 都具有不同的功能和使用上的一些限制,這就需要在不同的情景下使用最適合的并發(fā)方式。同時,這些 api 本身處在不同的

10、抽象層級上。我們很可能會使用它們進行一些特別底層的操作,但同時也意味著將背負起處理好這些操作的責任。為了利用多核,計算機需要軟件能夠同時干多件事情?,F(xiàn)代的多任務操作系統(tǒng),可以有上百的程序在給定的時間內運行,所以可以調度每個程序執(zhí)行在不同的核上。然而,大多數(shù)的程序屬于系統(tǒng)駐守進程,或那些運行在后臺,只需要很少 cpu 時間的程序。相反,真正的需要是為單個應用程序高效地使用處理器額外的核心。應用程序利用多核的傳統(tǒng)方式是創(chuàng)建多個線程,然而,由于核心的增加,有許多線程相關的問題需要解決,最大的問題是線程代碼不能很好的拓展到任意數(shù)目的核心。不能創(chuàng)建很多的線程,然后認為程序會很好的運行這些線程。我們無法確

11、認具體使用多少個核心才是最高效的,程序本身也無法很好地通過計算得出這個數(shù)值。即使得到了正確的數(shù)字,想要這么多線程之間不能干擾且高效運行,仍然具有很大的難度。所以我們需要一種抽象層次比線程高,同時效率又不能比線程太低的方式來處理并發(fā)。1.3論文章節(jié)安排在過去,在程序中引入并發(fā)需要創(chuàng)建額外的一個或多個線程。不幸的是,寫線程級別的代碼很具有挑戰(zhàn)性。線程是很底層的工具,必須手動來管理。對于一個程序,由于線程的最佳數(shù)目基于系統(tǒng)負載和底層硬件而動態(tài)改變,因此實現(xiàn)一個正確的線程解決方案是非常困難和復雜的。此外,線程的同步機制通常會給軟件設計增加復雜性和帶來風險,有時候并不能保證一定會提高程序性能。相比較傳統(tǒng)

12、的基于線程的系統(tǒng)和應用程序,os x 和 ios 更多地采用異步方法來執(zhí)行并行任務。應用程序只需要定義特定的任務,然后讓系統(tǒng)執(zhí)行它們,而不是直接創(chuàng)建線程。通過讓操作系統(tǒng)來管理線程,使得應用程序具有了原生線程不可能具有的可擴展性,同時開發(fā)者也有了更加簡單高效的編程模式。論文主要介紹了ios平臺下并發(fā)編程的技術和技巧,包含以下章節(jié):1. 并行和程序設計:介紹了基本的異步程序設計和異步執(zhí)行自定義任務的技巧。2. operation queues(操作隊列):介紹如何使用 objective-c 對象封裝任務并且執(zhí)行。3. dispatch queue(調度隊列):在 c 語言編程環(huán)境中,如何并行地執(zhí)

13、行任務。4. dispatch sources:如何異步的處理系統(tǒng)事件。第二章 并發(fā)程序的設計早期的計算機執(zhí)行最小任務所需的時間單元取決于cpu的時鐘速度,但隨著cpu技術的發(fā)展以及處理器上的核心越來越密集,散熱和其他物理因素開始影響cpu的最大時鐘速度。因此廠商們開始將注意力轉移到如何在單個芯片上加入更多的處理器核心,即多核cpu,這樣單個芯片的性能將又得到提升,因而剩下的問題就是如何充分利用這些增加的核心。傳統(tǒng)意義上利用cpu多核特性的方式為創(chuàng)建多個線程,然而移動設備上的cpu受限于系統(tǒng)負載和散熱等其他因素,不可以創(chuàng)建大量的線程而又使得程序很好的運行。因此需要一種比較好的方式來解決移動端多

14、線程編程的問題。2.1摒棄線程線程是利用處理器多核特性最直接的方式,也是組成進程的子單元,操作系統(tǒng)的調度器可以對線程進行單獨的調度。但是線程無法解決如何彈性地執(zhí)行多個任務這個很普遍的問題,我們無法控制自己線程中的代碼在什么時候開始執(zhí)行,需要執(zhí)行多長時間,什么時候暫停。直接使用線程執(zhí)行任務的另一個問題是,如果線程中的代碼使用了框架或庫時,那么執(zhí)行任務所增加的線程總數(shù)有可能以指數(shù)級別增長。例如,在8核cpu中,創(chuàng)建8個線程完成某個任務,看起來似乎充分利用了cpu的多個核心,但是很有可能每個線程中用到的某個框架又創(chuàng)建了多個線程1。創(chuàng)建每個線程都會消耗一些內存和內核資源,因此如何動態(tài)地拓展線程數(shù)目就變

15、得尤為重要,我們期望根據(jù)系統(tǒng)負載和當前可用的資源能夠動態(tài)的控制當前活動線程的數(shù)量。如果把這項任務交由開發(fā)者,那么多線程編程將會變得更加復雜,因此,最好的方式是使用系統(tǒng)為我們提供的并發(fā)編程模型。為了不依賴于線程,ios中采用異步編程的方式來處理需要后臺運行的任務。異步這個概念已經(jīng)存在于計算機中很長時間了,主要用于執(zhí)行一些需要花費很長時間的任務,例如從磁盤中讀取文件,從網(wǎng)絡上獲取數(shù)據(jù)等。當異步函數(shù)被調用后,任務就會在后臺開始執(zhí)行,同時函數(shù)會立刻返回,同時繼續(xù)執(zhí)行后續(xù)的任務。當處于后臺中的任務執(zhí)行完成后,會發(fā)送通知給調用者(通常為函數(shù)回調),調用者在函數(shù)回調中處理任務完成后的相關操作。這種異步的方式

16、既不影響當前任務的執(zhí)行,又能利用額外的核心完成非常耗時的操作。在ios平臺下,apple已經(jīng)提供了幾種異步的編程技術,下面主要介紹這些技術。使用異步編程的技術之一為 gcd(grand central dispatch)。這項技術能夠將原本開發(fā)者需要編寫的線程管理代碼轉移到系統(tǒng)級別,開發(fā)者只需定義需要執(zhí)行的任務并將其添加到適合的調度隊列即可。gcd 負責創(chuàng)建線程并在線程上執(zhí)行任務所需的代碼,現(xiàn)在由于線程管理是系統(tǒng)的一部分,gcd接管了線程管理以及任務的執(zhí)行,因此這種方式要比傳統(tǒng)創(chuàng)建線程的方式高效一些,更重要的是極大地減輕了開發(fā)者的負擔。另一種使用異步編程的技術為 operation queue

17、,它是 objective-c 對象,如同調度隊列一樣,開發(fā)者只需定義需要執(zhí)行的任務然后將其添加到操作隊列中,操作隊列將負責任務的調度和執(zhí)行。跟 gcd 一樣,操作隊列處理所有線程管理的工作,并且高效地執(zhí)行任務代碼。2.2異步編程技術介紹下面主要介紹ios平臺中異步編程的幾種技術。2.2.1調度隊列dispatch queue調度隊列是一種基于c語言的自定義任務執(zhí)行機制。調度隊列串行或并行地執(zhí)行任務,任務開始執(zhí)行的順序與其添加順序一致。串行的調度隊列同一時間只能執(zhí)行單個任務,需要等待上個任務完成后才可以開始下個任務的執(zhí)行。并行的調度隊列在同一時間內可以執(zhí)行多個任務,并不需要等待上個任務完成。調

18、度隊列具有以下優(yōu)點:1. 簡潔明了的編程接口。2. 自動全面的線程池管理方案。3. 可提供調度組件的速度。4. 更好的內存利用率(因為線程棧不處于應用程序本身內存區(qū))。5. 任務的異步調用不會導致死鎖。6. 競爭條件下?lián)碛懈线m的粒度。7. 串行隊列提供了更加有效的同步機制。提交到調度隊列中的任務必須封裝為block對象或者是一個函數(shù),調度隊列是gcdgcd和c運行時的一部分。2.2.2調度源dispatch sources調度源是用于異步處理特殊系統(tǒng)類型事件的基于c語言的機制。一個調度源封裝特殊系統(tǒng)類型事件的相關信息,當發(fā)生該事件時,向調度隊列提交函數(shù)或特殊的block對象。簡單來說,調度源

19、是一個監(jiān)視某些類型事件的對象。當這些事件發(fā)生時,它自動將一個block對象放入一個調度隊列的執(zhí)行例程中??梢允褂谜{度源來監(jiān)聽以下系統(tǒng)事件:計時器、信號處理描述符相關的進程事件、mach 端口事件和自定義的觸發(fā)事件2。2.2.3操作隊列operation queues操作隊列由ios中nsoperationqueue類實現(xiàn)。相比較調度隊列按照添加順序執(zhí)行任務,操作隊列在決定任務執(zhí)行順序時還會考慮其他一系列因素。提交到操作隊列的對象必須是nsoperation類的子類,nsoperation子類的對象封裝執(zhí)行的任務以及所需的數(shù)據(jù)。2.3異步編程設計在考慮將現(xiàn)有的代碼重新設計以支持并發(fā)時,首先應該確

20、認是否有這個必要。一般來說,并發(fā)將大多數(shù)耗時任務放至其他工作線程執(zhí)行,可以使得主線程空閑。由于ios中有關ui部分的事件都在主線程中處理,因此空閑的主線程能夠更加有效地處理相應用戶事件,使得界面更加流暢,提升用戶體驗,同時還能利用多核特性做更多的工作。當然,引入并發(fā)也會增加開銷和代碼量,增加編碼和debug難度。由于增加了軟件設計的復雜性,并發(fā)并不是產(chǎn)品開發(fā)周期快結束時需要加入的一個功能點。每一個程序都有不同的需求和指導任務,可以大概通過以下幾點來確認是否應該引入并發(fā)。2.3.1明確應用程序預期的行為在考慮程序中引入并發(fā)前,首先應該從明確程序正確的行為開始。了解程序預期的行為,在之后的設計中可

21、以幫助驗證設計的可行性。第一件事,就是羅列出程序所有要做的任務以及相關的數(shù)據(jù)結構。一開始,可能會從用戶的點擊事件任務開始,因為用戶點擊事件提供了很清晰的需求,用戶點擊了哪里,期望得到什么樣的行為。實際中更應該羅列其他無需用戶交互的應用程序任務,比如基于計時器的任務。當整理出較高級別任務的列表后,將任務再分解為完成所需的一系列步驟,在這個階段,應該是主要是對數(shù)據(jù)或者對象做一些修改,以及了解這些修改如何影響程序的整體狀態(tài)。還應該注意對象和數(shù)據(jù)結構之間的依賴關系,注意對一個對象的修改是否影響其他對象。2.3.2分解出任務的執(zhí)行單元在羅列程序任務時,應該基本明確哪些任務并發(fā)處理時會高效一些。如果整個任

22、務中更改了某些步驟的執(zhí)行順序,任務執(zhí)行結果會改變,那么可能需要考慮串行執(zhí)行這些步驟。如果任務的執(zhí)行結果與任務中步驟的執(zhí)行順序無關,那么可以使用并發(fā)來提高性能。這種情況下,將任務拆分出一步一步執(zhí)行的單元,然后將它們封裝成block或者operation對象并分發(fā)到對應的隊列。在確定任務中的每個執(zhí)行單元時,一開始不需要過多的擔心工作量是不是太大。即使開啟線程需要一定的開銷,但是調度隊列和操作隊列的一個優(yōu)點就是在多數(shù)情況下仍比傳統(tǒng)使用線程的方式開銷要小的多。所以,在使用隊列執(zhí)行一些很小的工作單元時,效率是高于使用線程的。當然,仍需要通過衡量實際運行時的效率來調整任務的大小,但是在一開始,沒必要考慮任

23、務單元是不是拆分得太小了。2.3.3決定需要分發(fā)任務的隊列現(xiàn)在已經(jīng)將任務拆分為工作單元,并且用block或者nsoperation對象封裝起來了。如果使用block封裝任務,可以向一個串行或并行的隊列添加block來執(zhí)行。如果對于執(zhí)行順序有特殊的要求,應該使用串行的隊列。如果工作單元對于執(zhí)行順序沒有要求,可以使用并發(fā)的隊列或者多個不同的并發(fā)隊列,具體取決于程序需求。如果使用nsoperation對象,那么配置對象將比選擇隊列更加重要。想要串行地執(zhí)行nsoperation對象,必須要先處理這些對象之間的依賴關系。依賴項會阻止當前操作繼續(xù)執(zhí)行,直到所依賴的對象完成它們的工作。2.4衡量引入并發(fā)后對

24、程序性能的影響調度隊列、操作隊列和調度源都提供了簡單的并發(fā)編程方式。然而這些技術并不能保證一定能夠提高程序的性能或改善代碼的執(zhí)行效率。因此仍然需要以一種合理的方式去使用并發(fā),且不能過度的使用操作系統(tǒng)資源。在代碼中引用并發(fā)之前,無論是使用隊列還是線程,都應該采集一些基準的性能指標反映當前的程序性能。當使用并發(fā)后,采集并發(fā)后的性能指標與之前的基準進行比較,看并發(fā)的引入是否提高了程序性能,推薦使用性能測試工具來檢測。2.5何時使用原生線程雖然操作隊列和調度隊列是執(zhí)行并發(fā)的首選方式,但這并不是適用于任何情況的。根據(jù)應用程序任務需求的不同,有時候可能仍需創(chuàng)建自定義的線程。如果的確有這個需要,那么盡可能使

25、用更少的線程,盡量不要使用線程做其他的操作。線程仍然是實現(xiàn)代碼運行在確定時間的最佳方式,調度隊列盡管會盡可能快速地執(zhí)行任務,但是仍然不能解決真實時間約束。如果需要了解更多線程運行在后臺的預計行為,線程通常會提供更好的選擇。不過,使用線程時最好再次確認其必要性。第三章 操作隊列在ios平臺中,cocoa 框架中的 nsoperation 通過面向對象的方式封裝了執(zhí)行異步操作的工作,主要用于 operation queue。本章節(jié)主要介紹 nsoperation 類的使用以及自定義子類化。3.1nsoperation對象簡介operation對象是nsoperation類的實例,用來封裝程序中需要

26、異步執(zhí)行的一些操作。nsoperation是抽象基類,所以不能直接使用,需要通過繼承實現(xiàn)自己的子類來執(zhí)行任務。由于基類本身已經(jīng)實現(xiàn)了一些基本操作,所以可以很方便地繼承它。除此之外,cocoa 框架還提供了兩個已經(jīng)定義好的子類,用于一些常用的異步操作,可以在代碼中直接使用它們3。第一個子類為nsinvocationoperation,基于一個方法選擇子和對象創(chuàng)建的對象,當程序中已經(jīng)存在現(xiàn)有的方法,并且希望異步執(zhí)行時,是一個較好的選擇。第二個子類為nsblockoperation,可以使用這個類并發(fā)地執(zhí)行一個或多個block對象。當所有相關的block執(zhí)行完畢后,operation對象才完成。當上

27、面提供的兩個類不能滿足需求時,可以考慮定義自己的nsoperation子類。這樣可以獲得更多有關操作對象的控制權,通常用于一些比較復雜的操作。所有的操作對象都支持以下重要的功能:1.支持操作對象間建立基于圖論的依賴關系,這些依賴項會阻止當前對象的運行,直到對象所依賴的其他項都完成。2.支持一個可選的completion block,當操作對象的主任務完成時調用。3.支持監(jiān)聽操作對象狀態(tài)的改變,需要操作對象使用 kvo。4.支持優(yōu)先級,會影響操作對象的執(zhí)行順序。5.支持取消操作對象的執(zhí)行,正在執(zhí)行時也可以取消。操作對象旨在提高程序的并發(fā)性,同時也是一種很好的封裝應用程序行為的方式。應該提交操作對

28、象到操作隊列上,讓它們在單獨的線程或者多個線程上執(zhí)行相應的工作,而不是在主線程上做大量的操作。3.2子類化nsoperation nsoperation類為所有的操作對象提供了一些基本的子類化點。同時提供了大量的基礎方法用于實現(xiàn)kvo依賴,然而,有時候仍需補充現(xiàn)有的基礎結構,來確保業(yè)務的正常運行。其他一些額外的工作量取決于是否實現(xiàn)并發(fā)操作。定義非并發(fā)的操作要比并發(fā)簡單的多,對于非并發(fā)的操作,只需要執(zhí)行主要任務并實現(xiàn)取消方法。對于并發(fā)操作,必須重載現(xiàn)有的一些代碼,下面各節(jié)主要講述重載的內容。3.2.1執(zhí)行主任務每個操作對象至少需要實現(xiàn)初始化和主任務這兩個方法,通過這兩個方法,操作對象可以實例化并

29、且得到一個需要執(zhí)行的任務。代碼示例如下: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 / 根據(jù)當前操作對象的數(shù)據(jù)進行處理,得出結果 catch(.) / 不要在這

30、里拋出異常 end3.2.2實現(xiàn)取消操作當操作對象開始執(zhí)行后,只有顯示地取消時,才會真正結束執(zhí)行。取消操作可以發(fā)生在任何時間,甚至在操作對象還未開始執(zhí)行時。盡管nsoperation抽象基類已經(jīng)提供了取消操作,但是應該在子類中重載它,并在取消操作中釋放已經(jīng)占有的資源。操作對象應該在整個執(zhí)行周期中檢查是否有取消事件發(fā)生,并且優(yōu)雅地處理該事件。支持取消需要做的就是在代碼中周期性的調用操作對象的 iscancelled 方法,并且當不返回yes時立刻返回。支持取消操作是很重要的,iscancelled方法調用返回非??欤虼丝梢灶l繁的調用而不會造成額外的開銷??赡苄枰谝韵碌胤秸{用iscancell

31、ed方法:1. 在執(zhí)行任何自然操作時立刻調用。2. 在循環(huán)中至少調用一次,或者當循環(huán)耗時較長時調用多次。3. 任何可能中斷操作的地方。3.2.3配置操作對象使其并發(fā)執(zhí)行默認情況下操作隊列以同步方式執(zhí)行,也就是說它們在調用start方法的線程上執(zhí)行任務。操作隊列為非并發(fā)的任務提供了線程,不過現(xiàn)在大多數(shù)操作需要異步運行,因此需要重載一些方法。下面列出了并發(fā)執(zhí)行時需要重載的方法:start :(必須)所有的并發(fā)操作必須重載這個方法,實現(xiàn)自定義的行為。通過調用start方法手動執(zhí)行操作。因此,這個方法的實現(xiàn)是操作開始執(zhí)行的起點,并且是設置線程或者其他運行環(huán)境的地方。需要注意的是任何時候都不能調用sup

32、er。main:(可選)這個方法通常用于實現(xiàn)操作對象相應的任務。盡管可以在start方法中實現(xiàn)這些任務,但是將其轉移到這里會有較好的代碼結構,使得操作對象的準備工作和執(zhí)行階段分開。isexecuting、isfinished:(必須)并發(fā)操作應該建立運行環(huán)境并且報告狀態(tài)給外面的用戶,然而,一個并發(fā)操作必須維護一些狀態(tài)信息,來了解何時開啟任務,何時完成任務。這些方法的實現(xiàn)必須是線程安全的,可能與kvo有關4。isconcurrent:重載并且返回yes即可。下面的代碼示例簡單的實現(xiàn)了如何子類化一個并發(fā)的操作對象:/ 子類化 nsoperationinterface myoperation: ns

33、operation bool executing;bool finished;- (void)completeoperation;endimplementation myoperation/ 實現(xiàn)初始化方法- (id)init self = super init;if (self) executing = no;finished = no;return self;/ 重載操作對象的并發(fā)性屬性- (bool)isconcurrent return yes;/ 重載實現(xiàn) kvo- (bool)isexecuting return executing;- (bool)isfinished retur

34、n finished;下面的代碼示例為如何在start方法中做準備工作,以及實現(xiàn)kvo:- (void)start / 周期性的檢查是否有取消操作發(fā)生if (self iscancelled) / 如果當前操作對象被取消,那么需要改變finished狀態(tài)信息self willchangevalueforkey:”isfinished”;finished = yes;self didchangevalueforkey:”isfinished”;/ 當取消操作發(fā)生時,需要直接返回return;/ 當操作對象沒有被取消時,開始執(zhí)行任務self willchangevalueforkey:”isexe

35、cuting”;/ 開啟單獨的線程并執(zhí)行任務nsthread detachnewthreadselector:selector(main) totarget:self withobject:nil;/ 這個時候任務已經(jīng)開始了,需要改變executing狀態(tài)executing = yes;self didchangevalueforkey:”isexecuting”;當編寫完操作對象的準備階段的start方法后,就可以開始編寫main方法,將start方法和main方法分開使得代碼有清晰的結構,有助于調試和debug。在main方法中,當操作對象的狀態(tài)改變時,仍需實現(xiàn)對象的kvo規(guī)則,如下:-

36、(void)main try / 開始執(zhí)行有關操作的主任務/ 執(zhí)行完成后調用完成操作self completeoperation;catch() / 仍然無需拋出異常- (void)completeoperation self willchangevalueforkey:”isfinished”;self willchangevalueforkey:”isexecuting”;/ 在任務完成后,需要更改對應的狀態(tài)信息executing = no;finished = yes;self didchangevalueforkey:” isfinished”;self didchangevaluef

37、orkey:” isexecuting”;3.2.4保證kvo規(guī)則nsoperation 對于以下屬性實現(xiàn) kvo:iscancelled、isconcurrent、isexecuting、isfinished、isready、dependencies、queuepriority、completionblock。如果對nsoperation重寫了start方法或者做了其他一些重大的定制,除了重載main方法,還需要確保自定義對象仍然保證了kvo規(guī)則。如果想要實現(xiàn)對其他操作對象依賴項的支持,可以重載isready方法,直到自定義的依賴項已經(jīng)滿足,不然一直返回no(這里應該調用super),當狀態(tài)

38、改變時,通過發(fā)出kvo通知告知狀態(tài)的改變。除非你重寫 adddependency 或 removedependency 方法,不然無需操心dependencies的kvo規(guī)則5。盡管可以生成其他key的 kvo,但是最好不要這樣做。如果需要取消操作對象,只需調用其cancel方法即可,同樣,整個過程可能不需要修改隊列優(yōu)先級。最后,除非操作對象會動態(tài)改變isconcurrent屬性,不然無需實現(xiàn)其kvo規(guī)則。3.3自定義操作對象的執(zhí)行行為成功建操作對象后,在將其添加到隊列之前,可以對操作對象進行配置。這一節(jié)中所描述的配置類型既可以應用于自定義的繼承于nsoperation類的子類,也可應用于系統(tǒng)

39、提供的子類。3.3.1配置操作對象之間的依賴關系依賴關系是一種序列化不同操作對象的方式。一個對象依賴于其他對象的執(zhí)行狀態(tài),只有當其依賴的對象全部完成時,它自己才可以開始執(zhí)行。因此,可以使用依賴關系來創(chuàng)立復雜的執(zhí)行順序。使用nsoperation類的adddependency:方法創(chuàng)建兩個對象之間的依賴關系。這個方法創(chuàng)建一個從當前對象到目標對象單向的依賴關系,其返回結果可以作為一個參數(shù)來傳遞。這種依賴性表示當前的對象只有在目標對象完成時才可以開始執(zhí)行。這種依賴關系并不局限于同一個隊列中的操作對象,因為操作對象本身管理自己的依賴項,所以,完全可以在不同隊列中的不同操作對象之間創(chuàng)建依賴關系。需要注意

40、的是,不要產(chǎn)生循環(huán)依賴的關系。當所有的依賴項都已經(jīng)完成時,當前操作對象將準備開始執(zhí)行(當重載isready方法后,這個狀態(tài)需要使用自己創(chuàng)建的標準)。如果對象已經(jīng)處于隊列中,那么隊列可能隨時開始執(zhí)行這個對象,如果是手動管理對象的執(zhí)行,那么需要調用操作對象的start方法。應該總是在操作對象運行之前或者添加到隊列之前配置它的依賴關系,在運行之后添加依賴關系可能會無效。依賴關系依賴于每個對象當狀態(tài)變化時發(fā)送kvo通知,當自定義對象的這種行為時,為了避免出錯,可能需要在代碼中生成對應的kvo通知。3.3.2更改操作執(zhí)行的優(yōu)先級對于添加到隊列的操作對象,執(zhí)行順序首先取決于已經(jīng)入隊操作對象的準備情況,然后

41、取決于其優(yōu)先級。準備情況取決于操作對象依賴的其他對象,但是優(yōu)先級是操作對象自身的屬性,默認情況下,所有新創(chuàng)建的操作對象都有一個默認的優(yōu)先級,但可以通過setqueuepriority方法增大或者減小優(yōu)先級。優(yōu)先級只適用于同一個隊列中的不同對象,如果程序中有多個操作隊列,每個對象在不同的隊列中的優(yōu)先級是相互獨立的。因此,低優(yōu)先級的操作對象可能在不同的隊列中執(zhí)行得比高優(yōu)先級的操作對象要早。優(yōu)先級不是依賴關系的替代,優(yōu)先級只影響某個隊列中已經(jīng)做好執(zhí)行準備的操作對象,舉個例子,如果一個隊列中,存在已經(jīng)準備好的兩個不同優(yōu)先級的對象,那么首先執(zhí)行高優(yōu)先級的,但如果高優(yōu)先級的還未準備好,低優(yōu)先級的已經(jīng)準備好

42、了,那么首先會執(zhí)行低優(yōu)先級的,如果想要使某個操作對象必須在另一個操作對象執(zhí)行完畢之后才執(zhí)行,那么應該使用依賴關系而不是優(yōu)先級。3.4開始執(zhí)行操作對象當操作對象初始化并且配置完成后,需要執(zhí)行它們來完成程序中的工作。3.4.1更改操作執(zhí)行的優(yōu)先級到目前為止,執(zhí)行操作對象最簡單的方式就是將其添加到一個操作隊列,應用程序本身負責創(chuàng)建和維護需要使用的操作隊列。程序可以擁有多個操作隊列,但如果太多會有限制。操作隊列與系統(tǒng)根據(jù)內核和系統(tǒng)負載,決定某一時刻維持多少并發(fā)的數(shù)量,因此,創(chuàng)建太多的操作隊列不一定能夠立即執(zhí)行其中的操作對象。創(chuàng)建隊列與創(chuàng)建其他對象的方式一樣。可以使用addoperation:方法添加操

43、作對象,同時還可以使用 addoperationwithblock:方法添加block,所有這些方法均進隊一個操作對象并開始執(zhí)行。大多數(shù)情況下,操作對象會在添加到隊列后就開始執(zhí)行,但是仍然還有其他一些原因可能會導致操作對象被推遲執(zhí)行。例如某個操作對象依賴于其他操作對象的完成,或者操作隊列本身是被掛起的,亦或是操作數(shù)超過了隊列設置的最大并發(fā)數(shù)。一定要注意當操作對象添加到操作隊列后,不能去改變它,你可以使用nsoperation類的其他方法來查看它當前的狀態(tài)。盡管操作隊列是并發(fā)的,但是仍然可以通過設置其最大并發(fā)數(shù)為1使其強制串行執(zhí)行,盡管同一時間只有一個操作對象執(zhí)行,但是其執(zhí)行順序仍然受其他因素的

44、影響,因此串行的操作隊列并不能提供像gcd一樣的行為,如果串行隊列中操作對象之間的執(zhí)行順序很重要,那么使用依賴關系仍然是最適合的方式。3.4.2手動實行操作對象盡管操作隊列可以很方便地執(zhí)行操作對象,但是有時候仍希望不通過操作隊列來執(zhí)行某些操作對象,下面是一些手動執(zhí)行需要注意的地方,最重要的是必須要保證其準備好執(zhí)行然后調用其start方法。操作對象不會在isready方法返回yes之前執(zhí)行,isready方法取決于其依賴的對象是否全部執(zhí)行完畢。手動執(zhí)行時必須顯示調用其start方法,不能使用main或者其他方法,因為start方法在真正運行前做了一些檢查,尤其是start方法中實現(xiàn)了有關kvo通

45、知的生成,保證了其他對象正確的依賴狀態(tài),此方法同時還保證了在取消之后不去執(zhí)行或者沒有準備好執(zhí)行時拋出異常。如果程序中定義了一些并發(fā)的操作對象,那么應該考慮在加載之前調用其isconcurrent方法,當它返回no時,就能夠決定是在當前線程同步執(zhí)行操作對象還是開啟另一個線程。下面的例子簡單的示范了手動執(zhí)行操作對象時的一些檢查工作,當方法返回no時,應該考慮實現(xiàn)定時器來重復調用直到返回yes。- (bool)performoperation:(nsoperation *)anopbool ranit = no;/ 檢查操作對象的狀態(tài)if (anop isready && !anop

46、 iscancelled)/ 當操作對象準備好并且沒有被取消時if(!anop isconcurrent) / 操作對象為串行執(zhí)行時,直接調用start方法anop start;else nsthread detachnewthreadselector:selector(start) totarget:anop withobject:nil;ranit = yes;else if (anop iscancelled) / 操作對象被取消,需要發(fā)出kvo通知并且改變執(zhí)行狀態(tài)self willchangevalueforkey:”isfinished”;self willchangevaluefo

47、rkey:”isexecuting”;executing = no;finished = yes;self didchangevalueforkey:” isfinished”;self didchangevalueforkey:” isexecuting”;ranit = yes;return ranit;3.4.3取消操作對象的執(zhí)行一旦操作對象添加到操作隊列后,將由操作隊列高效地管理并且不能被移除,唯一出隊的方式就是取消它,可以通過調用其cancel方法取消單個的操作對象,也可以調用操作隊列的cancelalloperation方法取消隊列中所有的操作對象。只有在確定不再需要時才取消它,取

48、消其實相當于操作對象已經(jīng)完成,如果被依賴項被取消,那么這個依賴關系就不再成立了。3.4.4等待操作對象執(zhí)行完成為了程序有更出色的表現(xiàn),應該讓操作對象盡可能的并發(fā),好讓程序能夠去做別的事情,如果創(chuàng)建操作對象的代碼同時需要等待執(zhí)行完成來處理執(zhí)行結果,可以調用waituntilfinished方法。但是盡量避免使用這個方法。永遠不能在程序主線程中等待操作對象完成,應該在工作線程或者其他操作對象中等待,因為阻塞主線程會使程序遲鈍。除了等待單個操作對象完成,也可以等待整個操作隊列完成,然后可以繼續(xù)向其添加操作對象。3.4.5掛起和恢復操作隊列如果需要暫停某個操作對象的執(zhí)行,可以使用隊列的setsuspe

49、nded方法,掛起隊列不會影響已經(jīng)執(zhí)行的操作對象,只會暫停新添加到隊列中的操作對象。第四章 調度隊列在ios平臺中,gcd 調度隊列是執(zhí)行任務的強大工具,可以使用同步或異步方式執(zhí)行任意的代碼塊。調度隊列可以執(zhí)行幾乎所有的單線程代碼。相比于線程級別代碼,其更易于使用,且效率要高。本章節(jié)將介紹調度隊列,以及如何使用它執(zhí)行大多數(shù)任務。4.1調度隊列介紹調度隊列是在程序中執(zhí)行同步或異步代碼的比較簡單的一種方式,任務就是程序中需要執(zhí)行的一些簡單的工作,例如執(zhí)行一些計算,創(chuàng)建或修改一個數(shù)據(jù)結構,從文件中讀取數(shù)據(jù)并進行處理等等這樣的一些工作。通過在函數(shù)或block中寫入相應的代碼來定義任務,然后將其添加至調

50、度隊列開始執(zhí)行。調度隊列是一種類似對象的結構,它管理提交到它上的任務。所有的調度隊列都是先進先出的,因此任務開始執(zhí)行的順序與添加順序一致。gcd已經(jīng)提供了一些常用的調度隊列,也可以根據(jù)自己的需求創(chuàng)建自定義調度隊列。當程序中引入并發(fā)性時,相比較線程而言,調度隊列提供了幾個特有的優(yōu)勢。最直接的優(yōu)勢就是簡單的工作隊列以及編程模型。使用線程時,不僅需要編寫執(zhí)行任務所需的代碼,還需創(chuàng)建和管理自己創(chuàng)建的線程。調度隊列能夠讓開發(fā)者更加專注于任務的處理,而無需擔心線程的管理和創(chuàng)建。相反,操作系統(tǒng)會做所有線程相關創(chuàng)建和管理的工作。相比于應用程序本身,操作系統(tǒng)能夠更加高效地管理線程,系統(tǒng)能夠根據(jù)可用的資源以及當前

51、的并發(fā)線程數(shù)量,動態(tài)地擴展正在運行線程的數(shù)量。此外,系統(tǒng)提供的線程通常會比自己創(chuàng)建的線程更快地開始執(zhí)行。使用調度隊列編碼要比線程簡單的多,其編碼的關鍵是設計能夠異步執(zhí)行且資源就緒的任務。然而,調度隊列還有個優(yōu)點是可預測性,如果有兩個不同的線程需要存取同一份資源,那么每個線程都有可能先修改這份資源,所以需要使用鎖來保證兩個線程不會同時修改這份資源。而使用調度隊列時,可以將這兩個任務添加進同一條串行隊列來確保同時只有一個任務可以修改資源。這種基于同步機制的隊列要比鎖的效率更高一些,因為鎖不管是不是在競爭條件下都需要一個昂貴的內核中斷。而調度隊列運行在自己的程序空間中,只有在必要時才會中斷內核。下面

52、是調度隊列其他一些需要重點關注的地方:1. 所有調度隊列同時執(zhí)行它們隊列中的任務,只有單個隊列中才會執(zhí)行序列化的任務。2. 系統(tǒng)決定同一時間類可以執(zhí)行任務的總數(shù)。3. 系統(tǒng)在選取新的任務執(zhí)行時會考慮隊列的優(yōu)先級。 4. 添加到隊列的任務必須滿足可以執(zhí)行的條件,比如資源就緒等。下面列出了幾種調度隊列,并相應做了簡要的說明。4.1.1串行隊列(serial queue)串行隊列,也稱私有調度隊列,執(zhí)行順序為任務添加的順序。當前正在執(zhí)行的任務運行在別的線程上(具體跟任務類型有關),并且由調度隊列直接進行管理。串行隊列經(jīng)常用來執(zhí)行一些同步操作,比如對于指定資源的存取。4.1.2并行隊列(concurr

53、ent queue)并行隊列,也稱全局隊列,可以同時執(zhí)行一個或多個任務。但任務仍然按照添加的順序執(zhí)行,當前的任務運行在不同的線程上,這些線程由調度隊列管理。某個時刻正在執(zhí)行的任務數(shù)量是變化的,取決于操作系統(tǒng)當前的狀態(tài)。在ios 5以后,可以指定調度隊列類型為 dispatch_queue_concurrent來創(chuàng)建自己的并發(fā)調度隊列,除此之外,系統(tǒng)已經(jīng)提供了四個預先定義的調度隊列供使用。4.1.3主調度隊列(main dispatch queue)主調度隊列是全局可用的串行隊列,在程序的主線程上執(zhí)行任務。與應用程序的其他事件執(zhí)行交織在一起加入到主線程的runloop中。由于隊列運行在主線程中,所以經(jīng)常用作一些關鍵的同步點。盡管不需要創(chuàng)建自己的主隊列,但是需要確保程序能夠在主線程中快速地執(zhí)行完所添加的任務,因為耗時的操作會阻塞ui,使得程序變得卡頓。4.2與隊列相關的一些技術點除了調度隊列外,gcd還提供了有關使用隊列編碼的一些技術,具體如下:dispatch group:用來觀察一組block對象的完成。它提供了一種非常有用的同步機制,依賴其他任務的完成。dispatch semaphores:類似于傳統(tǒng)的信號量,通常要高效一

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論