Swift — GCD 多執行緒

Tom Tung
6 min readJun 1, 2021

--

前言:

GCD 是 iOS 特殊的多執行緒管理機制,他將程式碼封裝到一個 block 區段,然後將 block 放到指定的佇列(queue),接下來系統會將 block 中的 code 依照佇列的特性及放進佇列的方式來決定是否要建立執行緒並開始執行。

簡單來說就是讓程式可以同時執行很多事,縮減執行任務所需時間,提供較佳的使用體驗,在運行時不會有停留在某個畫面的延遲感。

想一下,若有一個 app 將一大串 images 都堆放在主執行緒處理,那UI必須等到全部下載任務完成才會有反應,使用者便不會想繼續使用。

而在實作 GCD 時有個原則:

主執行緒必須總是維持在閒置狀態,用於應付使用者操作觸發的介面變化,任何耗時的任務應該跑在 concurrent 或是 background 的佇列。

名詞解釋 :

DispatchQueue

An object that manages the execution of tasks serially or concurrently on your app’s main thread or on a background thread.
- 官方文件

一個物件,用於管理任務在 app 的主線程或後台線程以串行或並行方式執行。

DispatchQueue 有三種類型:

  • Main queue
  • Global queue
  • Custom queue

下面會再進行說明。

佇列(queue):是資料結構的一種型態,特性是FIFO(先進先出)

Serial vs Concurrent

Serial(串行):按照順序來執行,前一個執行完成後,才會執行下一個。

Photo by Raywenderlich

Concurrent(並行):允許多個任務同時執行,工作會按順序「開始」執行,因為不需等上個工作執行完成,使得每個工作執行時間變得不可預測。

Photo by Raywenderlich

Synchronous vs Asynchronous

Sync(同步):等到區段中的程式碼全部執行完才 return。
簡單來說:queue(佇列)中的 code 只有在執行完畢後才會執行之後的 code

Async(非同步、異步):在執行一個程式區段時,不需等執行結束就立刻 return。
簡單來說:可以同時執行任務,一樣是按順序開始

說明:

從上述可以發現到,唯有在 Concurrent (並行)的 Queue 下,用 Async 執行才能同時執行多條任務。

Main queue

是一種 Serial queue(串行佇列) ,iOS 將所有跟 UI 元件有關的事件處理都放在 main 中 。
還有一點要注意的!在 main queue 必須使用 async(),否則會造成死鎖(deadlock)。

創建方式:DispatchQueue.main

例子:

結果:

Global queue

Global queue 運行在後台線程,是一種 Concurrent queue(並行佇列),可使用 sync 或 async 執行 block 區段的 code ,依據 sync 或 async 來決定是否要產生新的執行緒。

Global queue 會用到 Quality Of Service(QoS)(調度優先級),用意是告訴系統哪個任務比較重要,需要優先去執行(但不會超過 Main queue 的優先度)

由高到低:

  • userInteractive
  • userInitiated
  • default
  • utility
  • background
  • unspecified

一般若沒特別設定系統會預設為 default

創建方式:DispatchQueue.global()// qos為預設
// DispatchQueue.global(qos: .default)

例子 1 (使用 async ):

結果:

例子 2 (比較 sync 與 async ):

結果:

例子 3 (比較不同的 qos ):

結果 :

Custom queue

Custom queue 運行在後台線程,預設為 Serial queue(串行佇列)

創建方式:DispatchQueue(label: "test")// label 隨便取名,預設為 serial ,qos為 .default
DispatchQueue(label: "test", qos: .userInteractive, attributes: .concurrent)
// qos為 .userInteractive
// Concurrent queue(並行佇列)

例子(使用兩個 queue, 為 serial 的類型 , async 連接):

結果:

--

--

Tom Tung

Hi, I’m Tom. I work as an iOS developer.