IOS學習總結(1)——關於併發

真煩人發表於2014-02-23

本文僅作為個人學習總結記錄使用!能力有限,難免會有疏漏和錯誤,還望指出。共同進步。

獨白

工作學習IOS已經有半年了,一直都想抽出時間記錄一下自己的學習和工作經驗,但都寫到一半,就沒有然後了。關於併發程式設計,其實國外國內已經有各種牛人總結過非常棒的文章,但大多都是碎片化的文章。我就個人感受而言,總結一下併發程式設計以及相關的一些知識。

遇到的問題

關於併發程式設計,大部分的教程要麼是直接介紹GCD(Grand Central Dispatch
),要麼就是上一大堆的Operation Queues,還有介紹Threads來完成併發。

  • 其實他們都能實現併發,但他們之間有什麼區別呢?又有什麼聯絡呢?
  • block和GCD的區別?
  • 關於delegate和block的使用

OS X和iOS中的併發程式設計

在移動和桌面作業系統中,蘋果提供了相同的併發程式設計API。 常用的分別是:pthread和NSThread,Grand Central Dispatch(GCD)以及NSOperationQueue
由於高層API是基於底層API構建的,所以首先將從底層的API開始介紹,然後逐步介紹高層API,不過在具體程式設計中,選擇API的順序剛好相反:因為大多數情況下,選擇高層的API不僅可以完成底層API能完成的任務,而且能夠讓併發模型變得簡單。

Threads
執行緒(thread)是組成程式的子單元,作業系統的排程器可以對執行緒進行單獨的排程。實際上,所有的併發程式設計API都是構建於執行緒之上的——包括GCD和操作佇列(operation queues)。

一般在工作中,都不會使用pthread和NSThread,因為使用pthread或NSThread會引發一個問題:你建立了8個執行緒,然後在這些執行緒中呼叫了框架程式碼,這些程式碼也建立了同樣的執行緒(其實它並不知道你已經建立好執行緒了),這樣會很快產生成千上萬個執行緒,最終導致你的程式被終止執行——執行緒實際上並不是免費的咖啡,每個執行緒的建立都會消耗一些內容,以及相關的核心資源
基於佇列的併發程式設計API:GCD和operation queue。它們通過集中管理一個執行緒池(被沒一個任務協同使用),來解決上面遇到的問題

Grand Central Dispatch
通過GCD,開發者不用再直接跟執行緒打交道了,只需要向佇列中新增block程式碼即可,GCD在後端管理著一個執行緒池。GCD不僅決定著哪個執行緒(block)將被執行,它還根據可用的系統資源對執行緒池中的執行緒進行管理——這樣可以不通過開發者來集中管理執行緒,緩解大量執行緒的建立,做到了讓開發者遠離執行緒的管理。
更多GCD的使用請參考:Low-Level Concurrency APIs

Operation Queues
操作佇列(operation queue)是基於GCD封裝的一個佇列模型。GCD提供了更加底層的控制,而操作佇列在GCD之上實現了一些方便的功能,這些功能對於開發者來說會更好、更安全。
關於Operation Queues比較好的文章:Common Background Practices

NSObject
如果你只想讓一些程式碼在後臺執行,NSObject也提供了方法。這些方法的名字中都有“performSelector:”,最簡單的就是“performSelectorInBackground:withObject:”,它能在後臺執行一個方法。它通過建立一個執行緒來執行方法。定義這些方法必須遵循一下限制:

  • 這些方法執行在各自的執行緒裡,因此你必須為這些Cocoa物件建立一個自動釋放池,而主動釋放池是與主執行緒相關的。(arc,請無視)

  • 這些方法不能有返回值,並且要麼沒有引數,要麼只能有一個引數。換句話說,你只能使用以下程式碼格式中的一種。

  1. -(void)myMethod;
  2. -(void)myMethod:(id)myObject;

記住這些限制,我們實現的程式碼應該如下所示:

-(void)myBackgroudMethod{
   @autoreleasepool{
   //todo
   }
}

-(void)myOtherBackgroudMethod:(id)myObject{
   @autoreleasepool{
   // TODO
   }
}

同時呼叫的時候,應該像這樣。

[self performSelectorInBackground:@selector(myBackgroudMethod) withObject:nil];

[self performSelectorInBackground:@ selector(myOtherBackgroudMethod:)  withObject: myObject];

這樣就完成了。當方法執行結束後,OC執行時會特地清理並棄掉執行緒。需要注意,方法執行結束後並不會通知你:這是比較簡單的程式碼

配合NSObject的

performSelectorOnMainThread

也能達到GCD的效果:

-(void)myOtherBackgroudMethod:(id)myObject{
   @autoreleasepool{
   // TODO
    [self performSelectorOnMainThread:@selector(updateUI:) withObject:obj waitUntilDone:YES];
   }
}

-(void)updateUI:(NSObject *)obj{
    // TODO
}

關於block

個人認為比較好的文章:
初識block:
Block劇終:Objective-C中的閉包性和匿名函式:

關於GCD和block之間的區別

Gcd說到底其實就是方便操作執行緒的一個開源庫,並使用了block當做引數來傳遞這一特性。
Block其實就是OC的匿名函式,並具有閉包的特性,而且可以很容易的獲取上下文的資訊。和gcd有著本質的區別

總結

以上都是我學習中的總結和註釋而已。篇幅不多,大多都是站在別人的肩膀上。主要是給自己回顧和完善知識體系用的。如果有不對的地方,歡迎指出。

參考文章:Concurrent Programming: APIs and Challenges

相關文章