由於技術的發展,現在搭載多核心處理器的手機系統越來越多。在這些系統上如果要利用其多核心的優勢讓自己的程式運行速度更快,那免不了要利用多線程技術。更普遍的,如果要讓一個耗時很長的操作不至於卡住使用者介面,我們一般會把這個操作移交到另一個線程上做。當然,從作業系統的角度上講,這個辦法是(幾乎)唯一的辦法,沒有任何錯誤。
然而,作業系統對於線程的理解和碼農們畢竟不一樣。作業系統對於線程的調度能力是普通代碼力所不能及的。這展現在幾個方面:第一,程式員很難根據核心數量的多少來動態適應自己的線程數量。第二:程式員很難根據核心的負載來動態適應自己線程的優先順序。能夠對多線程進行最好管理的,一定是作業系統本身。這些都是我們編寫優質多線程代碼的時候的困難。
面對這種情況,iOS 提供了非常好的解決方案。GCD 和 NSOperationQueue 就是這樣的方案。在利用 Dispatch Queue 以及 Operation Queue 的時候有這樣幾個好處
1.能減少你的使用者程式管理線程的開支
2.你可以不用寫線程建立相關的代碼
3.你可以不用寫工作調度相關的代碼
4.總的來說,你的代碼變的簡單了
以 Dispatch Queue 作為例子
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
能讓程式在另外一個線程上執行 block 中的代碼,並且能夠保證你提交給 queue 的代碼的執行順序不被打亂。一般來說,多線程編程裡的單次任務線程都可以被這個代替。iOS 自身提供了四個全域的並行隊列,以及當前非並行的主隊列,我們還可以自行建立各種優先順序的並行或非並行隊列。利用 dispatch_async 和 dispatch_sync 我們可以選擇自己的代碼究竟在哪個隊列裡執行。只要做稍微的安排就可以完成要很多行原生的線程編程代碼才能完成的工作。
同樣的,NSOperationQueue 也能提供類似的功能。然而在介面上來說,GCD 相比 Operation Queue 要更接近於原本的線程,它們所提供的功能也是 GCD 要更豐富一些。
當然,平行處理不僅僅是只有多線程才能做到。一個很簡單的例子就是,在這段時間我把 Android 代碼翻譯到 iOS 的時候,碰到了很多多線程代碼。這些多線程代碼都是和網路互動相關。而 iOS 所提供的 socket 都是基於 runloop 的並行 socket,這樣在每一個主線程的 runloop 裡我們都可以根據收到的包以及程式的狀態來判斷程式下一步應該執行的行為,而不需要真正的刻意把這個交給一個子線程去做。事實上,如果要談論多線程和 runloop 的優劣的話,我也不敢妄下斷言。因為每種方法的出錯率還有運行效率也和程式員本身的思維方式和編程習慣有關。雖然在原則上自然是 GCD 最優。但是在普通線程代碼和 runloop 裡選擇的話,我個人偏向 runloop
當然,也有其他的不能使用 NSOperationQueue 以及 GCD 的情況。對於前者來說,自然純 C 的代碼或者 C++ 的代碼裡是沒法用的。而對於後者來說,如果你的代碼是 C++ 代碼並且需要能直接在 iOS 和 Android 兩個平台上運行(就像是許多 OpenGL 代碼一樣),這種時候的並行編程就只能老老實實的寫多線程了。真是悲劇