swift詳解之十六-----------GCD基礎部分

GCD基礎部分

注:本節主要詳細講解線程同步的一些基本概念和GCD基礎部分


GCD (Grand Central Dispatch)
首先我們來了解處理線程中的一些基本概念 :

  • 串行:同時只能有一個任務被執行

  • 併發:同時可以有多個任務執行

  • 同步:同步任務會阻塞當前線程,知道任務完成

  • 異步:預定的任務會完成但不會等它完成,因此,一個異步函數不會阻塞當前線程去執行下一個函數。

  • 臨界區:就是一段代碼不能被併發執行,也就是,兩個線程不能同時執行這段代碼。(不同代碼去操作共享資源可能會變質)

  • 死鎖:多個線程卡住了 , 並等待對方完成或執行其它操作。第一個不能完成是因爲它在等待第二個的完成。但第二個也不能完成,因爲它在等待第一個的完成。

  • 線程安全:線程安全的代碼能在多線程或併發任務中被安全的調用,而不會導致任何問題

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

  • 併發與並行:併發代碼的不同部分可以“同步”執行。多核設備通過並行來同時執行多個線程;爲了使單核設備也能實現這一點,它們必須先運行一個線程,執行一個上下文切換,然後運行另一個線程或進程。這通常發生地足夠快以致給我們併發執行地錯覺

  • Queues 隊列:GCD 提供有 dispatch queues 來處理代碼塊,這些隊列管理你提供給 GCD 的任務並用 FIFO(先進先出) 順序執行這些任務。所有的調度隊列(dispatch queues)自身都是線程安全的,你能從多個線程並行的訪問它們。當你瞭解了調度隊列如何爲你自己代碼的不同部分提供線程安全後,GCD的優點就是顯而易見的。關於這一點的關鍵是選擇正確類型的調度隊列和正確的調度函數來提交你的工作。由於在串行隊列中不會有兩個任務併發運行,因此不會出現同時訪問臨界區的風險;相對於這些任務來說,這就從競態條件下保護了臨界區。所以如果訪問臨界區的唯一方式是通過提交到調度隊列的任務,那麼你就不需要擔心臨界區的安全問題了。

  • Concurrent Queues 併發隊列:在併發隊列中的任務能得到的保證是它們會按照被添加的順序開始執行,但這就是全部的保證了。任務可能以任意順序完成,你不會知道何時開始運行下一個任務,或者任意時刻有多少 Block 在運行。這完全取決於 GCD 。
    如果一個 Block 的執行時間與另一個重疊,也是由 GCD 來決定是否將其運行在另一個不同的核心上,如果那個核心可用,否則就用上下文切換的方式來執行不同的 Block 。

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

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

最後,你也可以創建自己的串行隊列或併發隊列。這就是說,至少有五個隊列任你處置:主隊列、四個全局調度隊列,再加上任何你自己創建的隊列。GCD 的“藝術”歸結爲選擇合適的隊列來調度函數以提交你的工作。

下面看下示例
Global Dispatch Queues

 let back = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
        let defual = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        let high = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
        let low = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);

        dispatch_async(back) {
            //後臺執行
        }
        dispatch_async(defual) {
            //後臺執行
        }
        dispatch_async(low) {
            //後臺執行
        }
        dispatch_async(high) {
            //後臺執行
        }

上面是全局後臺執行的幾種類型。可以設定級別

下面看看主線程。多用來刷新UI

        dispatch_async(dispatch_get_main_queue()) {
            //主線程執行
        }

用戶隊列

 let queue = dispatch_queue_create("myQueue", nil);
        dispatch_async(queue) {
            //後臺執行
        }

下面是延時執行

  let time = NSEC_PER_SEC*3
        let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(time))
        print(NSEC_PER_SEC)
        dispatch_after(popTime,dispatch_get_main_queue()) {
            //這裏的內容在3秒後執行
            print(2)
        }
        print(1)

這裏NSEC_PER_SEC = 1000000000
先輸出1 三秒後輸出2

dispatch_once 在單例模式中很有用哦 , 不用if判斷。加上這個就能保證 只執行一次了

 func onlyOnce(){
        struct Static {
            static var onceToken : dispatch_once_t = 0
        }
        dispatch_once(&Static.onceToken) {
            print("只會輸出一次哦")
        }
        print("多次輸出呀")
    }

這裏static變量保證用的是同一個token

         onlyOnce()
        onlyOnce()
        onlyOnce()
        onlyOnce()
        onlyOnce()

然後我們多次調用 。

只會輸出一次哦
多次輸出呀
多次輸出呀
多次輸出呀
多次輸出呀
多次輸出呀

dispatch_once中的代碼只執行了一次 。

以上就是今天總結的GCD基礎部分 。下次總結下高級部分

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