關於GCD

什麼是GCD?GCD的全名為Grand Central Dispatch

基本上就是執行緒管理中心。用比較不嚴謹的敘述來說的話,它就是幫助你處理多執行緒的管理器。 利用GCD,可以很方便地操控各種需要多執行緒的情境

GCD的運作原理

這邊姑且先不討論程式面的東西,先從抽象一點的地方來看。

基本上來說,GCD掌控了Queue,而Queue包含了Work Item,最後WorkItem就是要執行的Closure

Queue

Queue可以被翻成「佇列」,但是看了翻譯還是不知道是什麼意思。

可以想像成是去看電影的時候排隊的人潮,隊伍本身就是Queue

先排進去的人,就可以先買票。這就是 FIFO ( First In First Out ) 的概念。

Queue裡面放的是WorkItem,用買票的例子來解釋的話,就是你要買哪場的票這件事。

Queue又有分SerialConcurrent兩種

Serial:就是一次只執行一個WorkItem,在這個WorkItem還沒執行完之前,不會取下一個來執行。

Concurrent:自然就是相對於Serial,當第一個WorkItem被取出後,並不會等這個WorkItem被執行完,就接著取出下一個WorkItem,一直到這個Queue中所有WorkItem被拿出來執行為止(或是你吃光了所有系統可分配的Thread,也會被暫停)


講完了Queue的類型,再來就是Queue要怎麼執行WorkItem

這部分就分為 Sync(同步)Async(非同步) 兩種

Sync

當前的Queue會被擋住,不能往下執行,等待WorkItem被執行完以後,才會繼續往下執行。在這個時間點中只有一個Queue可以運作。

所以在用sync方法的時候一定要非常小心一個重點

如果當前的執行中的Queue是Serial,而且你又要拿來做sync的動作的話,就會造成Deadlock

舉個例子,下面這段程式如果用Main Queue來執行,就永遠不會執行到print

DispatchQueue.main.sync {
	print("never execute here")
}

發生的原因很簡單,因為當系統執行到DispatchQueue.main.sync這段的時候,系統就知道「阿,要塞住當前的Queue」也就是MainQueue,然後又叫MainQueue去做事。但是這時候Main Queue已經被塞住了,又怎麼能去print呢?

Async:非同步代表的是它不會塞住當前的執行緒 所以當Queue用非同步去執行WorkItem的時候,系統會開一條新的Thread去執行這個WorkItem,然後就繼續往下執行。

非同步程式可以保證當前的Thread執行不會被卡住,因為都會開一個新的Thread去執行WorkItem。但是非同步程式常常會遇到的就是他不會有返回值,所以很容易出現Callback Hell的狀況。不過這不是本篇要講的重點,後面寫PromiseKitRxSwift的時候再說。

舉幾個例子,這可以直接貼到Playground裡面來執行

func syncDemo() {
    print("do something before sync")
    
    DispatchQueue.global().sync {
        for _ in 0...5 { print("sync") }
    }
    
    print("do something after sync")
}

syncDemo()

結果是比較顯而易見的,就跟程式執行順序一致。

do something before sync
sync
sync
sync
sync
sync
sync
do something after sync

那麼用差不多的架構,只不過把sync換成async的話,會怎麼樣的?

func asyncDemo() {
    print("do something before async")
    
    DispatchQueue.global().async {       // <-- 注意這裡是async
        for _ in 0...5 { print("async") }
    }
    
    print("do something after async")
}

asyncDemo()

這邊就差很多了。

因為是另外開執行緒去做事,所以跟看到的結果就會有明顯差異

do something before async
do something after async
async
async
async
async
async
async

所以關於怎麼挑選自己要用的Queue,就可以從這四個裡面去兜出來。

具體的挑選就看自己的情境來決定。

本來還要寫一些DispatchGroup、訊號機等筆記的,但是寫的有點煩了。

要改的東西太多了,那麼就改天吧。