Objective C - 多線程

在iOS中每個進程啟動后都會建立一個主線程(UI線程),這個線程是其他線程的父線程。由于在iOS中除了主線程,其他子線程是獨立于Cocoa Touch的,所以只有主線程可以更新UI界面(新版iOS中,使用其他線程更新UI可能也能成功,但是不推薦)。iOS中多線程使用并不復雜,關鍵是如何控制好各個線程的執行順序、處理好資源競爭問題。常用的多線程開發有三種方式:

1.NSThread

2.NSOperation

3.GCD

三種方式是隨著iOS的發展逐漸引入的,所以相比而言后者比前者更加簡單易用,并且GCD也是目前蘋果官方比較推薦的方式(它充分利用了多核處理器的運算性能)。

GCD

Grand Central Dispatch (GCD)是Apple開發的一個多核編程的解決方法。在iOS4.0開始之后才能使用。GCD是一個替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術的很高效和強大的技術。現在的iOS系統都升級到7了,所以不用擔心該技術不能使用。

(一)NSThread的使用

優點:NSThread 比其他兩個輕量級

缺點:需要自己管理線程的生命周期,線程同步。線程同步對數據的加鎖會有一定的系統開銷。

NSThread 有兩種直接創建方式:第一個是實例方法,第二個是類方法。

第一種方式會直接創建線程并且開始運行線程;

第二種方式是先創建線程對象,然后再運行線程操作,在運行線程操作前可以設置線程的優先級等線程信息。

其他同步

我們可以使用指令 @synchronized 來簡化 NSLock的使用,這樣我們就不必顯示編寫創建NSLock,加鎖并解鎖相關代碼。還有其他的一些鎖對象,比如:循環鎖NSRecursiveLock,條件鎖NSConditionLock,分布式鎖NSDistributedLock等等,可以自己看官方文檔學習。

(二)Cocoa NSOperation的使用

Cocoa NSOperation

優點:不需要關心線程管理,數據同步的事情,可以把精力放在自己需要執行的操作上。

Cocoa operation 相關的類是 NSOperation ,NSOperationQueue。

NSOperation是個抽象類,使用 NSOperation的方式有兩種,一種是用定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。另一種是繼承NSOperation。

如何控制線程池中的線程數?

隊列里可以加入很多個NSOperation, 可以把NSOperationQueue看作一個線程池,可往線程池中添加操作(NSOperation)到隊列中。線程池中的線程可看作消費者,從隊列中取走操作,并執行它。線程池中的線程數,也就是并發操作數。默認情況下是-1,-1表示沒有限制,這樣會同時運行隊列中的全部的操作。

(三)GCD的介紹和使用

介紹:

Grand Central Dispatch 簡稱(GCD)是蘋果公司開發的技術,以優化的應用程序支持多核心處理器和其他的對稱多處理系統的系統。這建立在任務并行執行的線程池模式的基礎上的。它首次發布在Mac OS X 10.6 ,iOS 4及以上也可用。

通過 GCD,開發者不用再直接跟線程打交道了,只需要向隊列中添加代碼塊即可,GCD 在后端管理著一個線程池。GCD 不僅決定著你的代碼塊將在哪個線程被執行,它還根據可用的系統資源對這些線程進行管理。這樣可以將開發者從線程管理的工作中解放出來,通過集中的管理線程,來緩解大量線程被創建的問題。

GCD 帶來的另一個重要改變是,作為開發者可以將工作考慮為一個隊列,而不是一堆線程,這種并行的抽象模型更容易掌握和使用。

首先,系統提供給你一個叫做 主隊列(main queue) 的特殊隊列。和其它串行隊列一樣,這個隊列中的任務一次只能執行一個。然而,它能保證所有的任務都在主線程執行,而主線程是唯一可用于更新 UI 的線程。這個隊列就是用于發生消息給 UIView 或發送通知的。

系統同時提供給你好幾個并發隊列。它們叫做 全局調度隊列(Global Dispatch Queues) 。目前的四個全局隊列有著不同的優先級:background、low、default 以及 high。要知道,Apple 的 API 也會使用這些隊列,所以你添加的任何任務都不會是這些隊列中唯一的任務。

最后,你也可以創建自己的串行隊列或并發隊列。這就是說,至少有五個隊列任你處置:主隊列、四個全局調度隊列,再加上任何你自己創建的隊列。

GCD相比其他多線程有哪些優點?

GCD 能通過推遲昂貴計算任務并在后臺運行它們來改善你的應用的響應性能。

GCD 提供一個易于使用的并發模型而不僅僅只是鎖和線程,以幫助我們避開并發陷阱。

GCD 具有在常見模式(例如單例)上用更高性能的原語優化你的代碼的潛在能力。

GCD 會自動利用更多的CPU內核(比如雙核、四核)

GCD術語

串行(Serial):讓任務一個接著一個地執行(一個任務執行完畢后,再執行下一個任務)

并發(Concurrent):可以讓多個任務并發(同時)執行(自動開啟多個線程同時執行任務)并發功能只有在異步(dispatch_async)函數下才有效。

同步(Synchronous):在當前線程中執行任務,不具備開啟新線程的能力

異步(Asynchronous):在新的線程中執行任務,具備開啟新線程的能力

dispatch queue分為下面三種:

Serial:又稱為private dispatch queues,同時只執行一個任務。Serial queue通常用于同步訪問特定的資源或數據。當你創建多個Serial queue時,雖然它們各自是同步執行的,但Serial queue與Serial queue之間是并發執行的。

Concurrent:又稱為global dispatch queue,可以并發地執行多個任務,但是執行完成的順序是隨機的。

Main dispatch queue:它是全局可用的serial queue,它是在應用程序主線程上執行任務的。

1、常用的方法dispatch_async

為了避免界面在處理耗時的操作時卡死,比如讀取網絡數據,IO,數據庫讀寫等,我們會在另外一個線程中處理這些操作,然后通知主線程更新界面。用GCD實現這個流程的操作比前面介紹的NSThread? NSOperation的方法都要簡單。

系統給每一個應用程序提供了三個concurrent dispatch queues。這三個并發調度隊列是全局的,它們只有優先級的不同。因為是全局的,我們不需要去創建。我們只需要通過使用函數dispath_get_global_queue去得到隊列,如下:

dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

這里也用到了系統默認就有一個串行隊列main_queue:

dispatch_queue_t mainQ = dispatch_get_main_queue();

雖然dispatch queue是引用計數的對象,但是以上兩個都是全局的隊列,不用retain或release。

2、dispatch_group_async的使用

dispatch_group_async可以實現監聽一組任務是否完成,完成后得到通知執行其他的操作。這個方法很有用,比如你執行三個下載任務,當三個任務都下載完成后你才通知dispatch_group_notify界面說完成的了。dispatch_group_async是異步的方法,運行后可以看到打印結果。

3、dispatch_barrier_async的使用

dispatch_barrier_async是在前面的任務執行結束后它才執行,而且它后面的任務等它執行完成之后才會執行。

4、dispatch_apply

執行某個代碼片段N次。

總結:

- NSThread是早期的多線程解決方案,實際上是把C語言的PThread線程管理代碼封裝成OC代碼。

- GCD是取代NSThread的多線程技術,C語法+block。功能強大。

- NSOperationQueue是把GCD封裝為OC語法,額外比GCD增加了幾項新功能。

* 最大線程并發數

* 取消隊列中的任務

* 暫停隊列中的任務

* 可以調整隊列中的任務執行順序,通過優先級

* 線程依賴

* NSOperationQueue支持KVO。 這就意味著你可以觀察任務的狀態屬性。

但是NSOperationQueue的執行效率沒有GCD高,所以一半情況下,我們使用GCD來完成多線程操作。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容