iOS GCD(Grand Central Dispatch)的使用(1)

GCD優勢:

易用: GCD 提供一個易於使用的併發模型而不僅僅只是鎖和線程,以幫助我們避開併發陷阱,而且因爲基於block,它能極爲簡單得在不同代碼作用域之間傳遞上下文。

靈活: GCD 具有在常見模式上(比如鎖、單例),用更高性能的方法優化代碼,而且 GCD 能提供更多的控制權力以及大量的底層函數。
性能: GCD 能自動根據系統負載來增減線程數量,這就減少了上下文切換以及增加了計算效率。

GCD相關概念

  • Dispatch Objects:
    GCD是純C語言的,但它被組建成面向對象的風格。GCD對象被稱爲dispatch object, 所有的dispatch objects都是OC對象.,就如其他OC對象一樣,當開啓了ARC(automatic reference counting)時,dispatch objects的retain和release都會自動執行。而如果是MRC的話,dispatch objects會使用dispatch_retain和dispatch_release這兩個方法來控制引用計數。

  • Serial & Concurrent:
    串行任務就是每次只有一個任務被執行,併發任務就是在同一時間可以有多個任務被執行。

  • Synchronous & Asynchronous:
    同步函數 意思是在完成了它預定的任務後才返回,在任務執行時會阻塞當前線程。而 異步函數 則是任務會完成但不會等它完成,所以異步函數不會阻塞當前線程,會繼續去執行下一個函數。

  • Context Switch:
    Context Switch即上下文切換,一個上下文切換指當你在單個進程裏切換執行不同的線程時存儲與恢復執行狀態的過程。這個過程在編寫多任務應用時很普遍,但會帶來一些額外的開銷。

  • Dispatch Queues:
    GCD dispatch queues是一個強大的執行多任務的工具。Dispatch queue是一個對象,它可以接受任務,並將任務以先進先出(FIFO)的順序來執行。Dispatch queue可以併發的或串行的執行任意一個代碼塊,而且併發任務會像NSOperationQueue那樣基於系統負載來合適地併發進行,串行隊列同一時間則只執行單一任務。Dispatch queues內部使用的是線程,GCD 管理這些線程,並且使用Dispatch queues的時候,我們都不需要自己創建線程。Dispatch queues相對於和線程直接通信的代碼優勢是:Dispatch queues使用起來特別方便,執行任務更加有效率。

GCD三種隊列類型

(1) 主線程隊列: main queue可以調用dispatch_get_main_queue()來獲得。因爲main queue是與主線程相關的,所以這是一個串行隊列。和其它串行隊列一樣,這個隊列中的任務一次只能執行一個。它能保證所有的任務都在主線程執行,而主線程是唯一可用於更新 UI 的線程。

(2) 併發隊列: 併發隊列雖然是能同時執行多個任務,但這些任務仍然是按照先到先執行(FIFO)的順序來執行的。併發隊列會基於系統負載來合適地選擇併發執行這些任務。在iOS5之前,併發隊列一般指的就是全局隊列(Global queue),進程中存在四個全局隊列:高、中(默認)、低、後臺四個優先級隊列,可以調用dispatch_get_global_queue函數傳入優先級來訪問隊列。而在iOS5之後,我們也可以用dispatch_queue_create,並指定隊列類型DISPATCH_QUEUE_CONCURRENT,來自己創建一個併發隊列。

(3) 串行隊列: 串行隊列將任務以先進先出(FIFO)的順序來執行,所以串行隊列經常用來做訪問某些特定資源的同步處理。你可以也根據需要創建多個隊列,而這些隊列相對其他隊列都是併發執行的。換句話說,如果你創建了4個串行隊列,每一個隊列在同一時間都只執行一個任務,對這四個任務來說,他們是相互獨立且併發執行的。如果需要創建串行隊列,一般用dispatch_queue_create這個方法來實現。

介紹完基本概念,我們看看如何使用…..


創建和管理隊列

(1) global queue(全局隊列):
當我們需要同時執行多個任務時,併發隊列是非常有用的。併發隊列其實仍然還是一個隊列,它保留了隊列中的任務按先進先出(FIFO)的順序執行的特點。一個併發隊列中實際執行的任務數是由很多因素決定的,比如系統的內核數,其他串行隊列中任務的優先級,以及其他進程的工作狀態。但是global queue 對於 dispatch_suspend(暫停)、dispatch_resume(恢復)、dispatch_set_context(切換上下文)函數無響應

我們來看一看 dispatch queue隊列的優先級都有哪些

#define DISPATCH_QUEUE_PRIORITY_HIGH 2 //高

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 //默認

#define DISPATCH_QUEUE_PRIORITY_LOW (-2) //低

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN //後臺


注意:
儘管dispatch queues是引用計數對象,但是我們不需要用retain和release來管理全局的併發隊列。因爲全局隊列對於程序來說是全局的,retain和release會被全局隊列忽略,而且在ARC下這兩個方法也會被忽略的。所以,我們不需要存儲這些隊列的引用數,僅僅只需要在任何要使用它們的地方,調用dispatch_get_global_queue這個方法即可。

(2) 併發隊列和串行隊列
當我們需要某些任務以指定的順序去執行時,串行隊列是一個非常好的選擇。一個串行隊列在同一時間裏只會執行一個任務,而且每次都只會從隊列的頭部把任務取出來執行。正因爲如此,我們可以用串行隊列來替代鎖的操作,比如數據資源的同步或修改數據結構時。和鎖不同的是,串行隊列能保證任務都是在可預見的順序裏執行,而且一旦我們在一個串行隊列裏異步提交了任務,隊列就能永遠不發生死鎖。怎麼樣,是不是很棒,不過不像併發隊列,這些串行隊列是需要我們自己創建和管理的。

我們還可以在程序裏創建任意數量的隊列,不過值得注意的是,我們要儘量避免創建大量的串行隊列而目的僅僅是爲了同時執行隊列中的這些任務。雖然GCD 通過創建所謂的線程池來大致匹配 CPU 內核數量,但是線程的創建並不是無代價的。每個線程都需要佔用內存和內核資源。所以如果需要創建大量的併發任務,我們只需要把這些任務放到併發隊列中即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章