文章結(jié)構(gòu)
摘要:本文參考 Apple 官方文檔 Concurrency Programming Guide臭杰,從總體上介紹并發(fā)編程的相關(guān)內(nèi)容廓啊,涉及 NSOperation 和 GCD旷痕。
前言
并發(fā)(Concurrency)指的是多個事件同時發(fā)生并淋。當(dāng) App 有多個任務(wù)要完成時醋安,把其中一部分放在其他線程(Thread)里能充分利用 CPU 資源刁憋。
對于早期的計算機(jī)滥嘴,單位時間處理的任務(wù)量取決于 CPU 的時鐘頻率。但是隨著技術(shù)的發(fā)展至耻,單核 CPU 的時鐘頻率提升逐漸達(dá)到瓶頸若皱。因此 CPU 開始采用多核心的設(shè)計镊叁,來提高性能。
讓一個 App 使用多核心的傳統(tǒng)方法是創(chuàng)建多個線程走触,但是手動操作和管理線程晦譬,難度很大,并且很難保證性能饺汹,如:線程的數(shù)目要適當(dāng)蛔添,并且隨著系統(tǒng)運(yùn)行的狀態(tài)進(jìn)行調(diào)整。
為此 Apple 提供了以下幾種負(fù)責(zé)處理多核兜辞、多線程的解決方案:
- Grand Central Dispatch(GCD)迎瞧;
- Operation Queues;
- OpenCL 等逸吵。
GCD 與 Operation Queues
首先我們對比一下 GCD 與 Operation Queues凶硅。
GCD 基于 C 語言,它提供了簡潔的并發(fā)編程 API扫皱。
Operation Queues足绅,在 Cocoa 里對應(yīng) NSOperation 和 NSOperationQuque,是 Objective-C 類韩脑。它實(shí)現(xiàn)了類似于 GCD 的功能氢妈。
Operation Queues 最先引入,但是到了 OS 10.6 和 iOS 4段多,NSOperationQueue 的內(nèi)部代碼就使用 GCD 實(shí)現(xiàn)了首量。也就是說,在最新的 OS X 和 iOS 系統(tǒng)里进苍,NSOperation 其實(shí)就是使用了 GCD加缘,但它并不是簡單的調(diào)用 GCD,它還實(shí)現(xiàn)了一些復(fù)雜的方法觉啊。
Dispatch Queues
GCD 包含 Dispatch Queues 和 Dispatch Sources拣宏。
Dispatch Queues 的執(zhí)行方式有兩種:
- Concurrent(并發(fā),可以同時開始多個任務(wù))杠人;
- Serial(串行勋乾,一個任務(wù)完成后才開始下一個任務(wù))。
它們都是先入先出(FIFO)嗡善,需要把執(zhí)行的代碼放到函數(shù)或 Block 里市俊。
Dispatch Sources
Dispatch Sources 基于 C 語言,用于異步處理特殊類型的系統(tǒng)事件滤奈。當(dāng)事件發(fā)生時摆昧,dispatch source 會封裝一些系統(tǒng)事件的信息,通過函數(shù)或 Block 提交到 dispatch queue 里蜒程。幾種系統(tǒng)事件的類型如下:
- Timers
- Signal handlers
- Descriptor-related events
- Process-related events
- Mach port events
- Custom events that you trigger
Operation Queues
Dispatch Queue 總是以 FIFO 的順序執(zhí)行绅你,而 Operation Queue 可以通過設(shè)置參數(shù)伺帘,實(shí)現(xiàn)對執(zhí)行順序的控制。如:可以設(shè)定當(dāng)一個任務(wù)完成后忌锯,才能執(zhí)行下一個任務(wù)伪嫁;可以構(gòu)建復(fù)雜的執(zhí)行圖(Graph)。
提交給 Operation Queue 的任務(wù)是一個 NSOperation 的實(shí)例偶垮。NSOperation 本身是一個抽象的類张咳,NSInvocationOperation 和 NSBlockOperation 繼承自 NSOperation。因此似舵,我們可以使用 NSInvocationOperation 和 NSBlockOperation 或使用自己創(chuàng)建的 NSOperation 子類來創(chuàng)建任務(wù)脚猾。
還有,由于 NSOperation 繼承自 NSObject砚哗,且其對象會發(fā)出 KVO 消息龙助。所以可以通過 KVO 來檢測 Operation 的執(zhí)行情況。
異步設(shè)計技術(shù)
使用 Concurrency 能充分利用多核心蛛芥,讓主線程關(guān)注于用戶的操作提鸟,而把其他任務(wù)交給另外的線程。但是這會極大增加代碼的復(fù)雜度仅淑,并且加大維護(hù)難度称勋,因此要做出權(quán)衡。
確定要執(zhí)行的任務(wù)
進(jìn)行異步設(shè)計涯竟,首先確定 App 要完成的任務(wù)铣缠,按優(yōu)先級列出,并考慮它們之間的關(guān)系昆禽。
弄清任務(wù)的執(zhí)行步驟
考慮任務(wù)的每一步(Unit),分析是否能通過多線程優(yōu)化蝇庭,以及能得到多大的性能提升醉鳖。在不熟悉 NSThread(更底層的線程操作類) 的情況下,使用 queue 可能會比使用 NSThread 效果更好哮内。
確定 Queue 的類型
把任務(wù)分成各個步驟(Unit)后盗棵,把它們放到 Block 或 Operation Object 里,確定它們的執(zhí)行順序北发。
- 若使用 Block纹因,考慮添加到 Serial dispatch queue 或 Concurrency dispatch queue。
- 若使用 Operation Objects琳拨,queue 的選擇相比 operation object 的設(shè)置就不那么重要了瞭恰。主要設(shè)置好各個 object 之間的關(guān)系。
小技巧
- 考慮直接在進(jìn)行的任務(wù)中求值狱庇,而不用回到主線程獲取數(shù)值惊畏。由于線程的切換會有額外的開銷恶耽,應(yīng)避免頻繁切換線程;
- 盡早確定順序執(zhí)行的任務(wù)(serial tasks)颜启;
- 避免使用鎖(lock)偷俭;
- 盡量使用系統(tǒng)框架。
其它并發(fā)技術(shù)
OpenCL
OpenCL(Open Computing Language)是 OS X 上的一個并發(fā)技術(shù)缰盏,用于使用 GPU 進(jìn)行數(shù)值計算涌萤。如:利用 GPU 對一張圖片中的每個像素點(diǎn)進(jìn)行處理,計算出處理后的數(shù)值口猜。
需要注意的是负溪,使用 OpenCL 是有一定額外開銷的,把數(shù)據(jù)傳入 GPU 和從 GPU 獲取結(jié)果數(shù)據(jù)都需要時間暮的,因此不能濫用 OpenCL笙以。
何時使用線程(Threads)
雖然 Operation Queues 和 Dispatch Queues 在處理并發(fā)任務(wù)上很適用,但是它們并不是萬能的冻辩。根據(jù)實(shí)際的情況猖腕,有時需要手動創(chuàng)建線程,這樣能對線程有更精確的控制恨闪。關(guān)于線程的使用倘感,請參考 Threading Programming Guide。
參考:Concurrency Programming Guide咙咽。
有任何疑問的話老玛,歡迎在下方評論區(qū)討論。