天天看點

iOS多線程:GCD使用介紹

背景

最近作者在進行多線程問題排查和整理時,發現了好多問題都是由于GCD的使用不規範造成的,是以在這裡主要分享GCD的使用方法,希望大家能夠在測試時更早發現問題。

iOS多線程:GCD使用介紹

GCD簡介

GCD 為蘋果推出的多核程式設計解決方案,它不僅能夠自動利用多個核心處理資料,還能夠自動管理生命周期,不需要程式猿手動管理。在日常的程式設計中十分常用。其優點如下:

  • GCD 可用于多核的并行運算;
  • GCD 會自動利用更多的 CPU 核心(比如雙核、四核);
  • GCD 會自動管理線程的生命周期(建立線程、排程任務、銷毀線程);
  • 程式員隻需要告訴 GCD 想要執行什麼任務,不需要編寫任何線程管理代碼。

GCD 任務和隊列

學習 GCD 之前,先來了解 GCD 中兩個核心概念:『任務』 和 『隊列』。

任務:就是執行操作的意思,換句話說就是你線上程中執行的那段代碼。在 GCD 中是放在 block 中的。執行任務有兩種方式:『同步執行』 和 『異步執行』。兩者的主要差別是:是否等待隊列的任務執行結束,以及是否具備開啟新線程的能力。

  • 同步執行(sync):
    • 同步添加任務到指定的隊列中,在添加的任務執行結束之前,會一直等待,直到隊列裡面的任務完成之後再繼續執行。
    • 隻能在目前線程中執行任務,不具備開啟新線程的能力。
  • 異步執行(async):
    • 異步添加任務到指定的隊列中,它不會做任何等待,可以繼續執行任務。
    • 可以在新的線程中執行任務,具備開啟新線程的能力。

隊列(Dispatch Queue):這裡的隊列指執行任務的等待隊列,即用來存放任務的隊列。隊列是一種特殊的線性表,采用 FIFO(先進先出)的原則,即新任務總是被插入到隊列的末尾,而讀取任務的時候總是從隊列的頭部開始讀取。每讀取一個任務,則從隊列中釋放一個任務。隊列的結構可參考下圖:

iOS多線程:GCD使用介紹

在 GCD 中有兩種隊列:『串行隊列』 和 『并發隊列』。兩者都符合 FIFO(先進先出)的原則。兩者的主要差別是:執行順序不同,以及開啟線程數不同。

  • 串行隊列(Serial Dispatch Queue):
    • 每次隻有一個任務被執行。讓任務一個接着一個地執行。(隻開啟一個線程,一個任務執行完畢後,再執行下一個任務)
  • 并發隊列(Concurrent Dispatch Queue):
    • 可以讓多個任務并發(同時)執行。(可以開啟多個線程,并且同時執行任務)

兩者具體差別如下兩圖所示:

iOS多線程:GCD使用介紹
iOS多線程:GCD使用介紹

GCD 的使用步驟

GCD 的使用步驟其實很簡單,隻有兩步:

  1. 建立一個隊列(串行隊列或并發隊列);
  2. 将任務追加到任務的等待隊列中,然後系統就會根據任務類型執行任務(同步執行或異步執行)。

下邊來看看隊列的建立方法 / 擷取方法,以及任務的建立方法。

1. 建立隊列

可以使用 dispatch_queue_create 方法來建立隊列。該方法需要傳入兩個參數:

  • 第一個參數表示隊列的唯一辨別符,用于 DEBUG,可為空。隊列的名稱推薦使用應用程式 ID 這種逆序全程域名。
  • 第二個參數用來識别是串行隊列還是并發隊列。DISPATCH_QUEUE_SERIAL 表示串行隊列,DISPATCH_QUEUE_CONCURRENT 表示并發隊列。
// 串行隊列的建立方法           

複制

2. 任務的建立方法

GCD 提供了同步執行任務的建立方法

dispatch_sync

和異步執行任務建立方法

dispatch_async

// 同步執行任務建立方法
dispatch_sync(queue, ^{
    // 這裡放同步執行任務代碼
});
// 異步執行任務建立方法
dispatch_async(queue, ^{
    // 這裡放異步執行任務代碼
});           

複制

雖然使用 GCD 隻需兩步,但是既然我們有兩種隊列(串行隊列 / 并發隊列),兩種任務執行方式(同步執行 / 異步執行),如果目前代碼預設放在主隊列中,我們也有兩種特殊的組合方式。于是我們就有了六種不同的組合方式。這四種不同的組合方式是:

同步執行 + 并發隊列

異步執行 + 并發隊列

同步執行 + 串行隊列

異步執行 + 串行隊列

同步執行 + 主隊列

異步執行 + 主隊列

我們先來考慮最基本的使用,也就是目前線程為 『主線程』 的環境下,『不同隊列』+『不同任務』 簡單組合使用的不同差別。暫時不考慮 『隊列中嵌套隊列』 的這種複雜情況。

『主線程』中,『不同隊列』+『不同任務』簡單組合的差別:

任務 并發隊列 串行隊列 主隊列
同步(sync) 沒有開啟新線程,串行執行任務 沒有開啟新線程,串行執行任務 死鎖卡住不執行
異步(async) 有開啟新線程,串行執行任務 有開啟新線程(1條),串行執行任務 沒有開啟新線程,串行執行任務

總結

GCD的使用看起來非常簡單,但是在實際使用當中必須要嚴格遵循隊列和任務的關系,以及内部資料的線程安全,防止出現機率崩潰及鎖死的情況。GCD雖然非常好用,但也意味着其産生問題時會造成更大的影響,希望大家在測試過程中重點關注。