Swift - 多線程實現方式 - Grand Central Dispatch(GCD)

1,Swift繼續使用Object-C原有的一套線程,包括三種多線程編程技術:

(1)Thread

(2)Cocoa Operation(Operation和OperationQueue)

(3)Grand Central Dispath(GCD)

2,本文著重介紹Grand Central Dispath(GCD)

GCD是Apple開發的一個多核編程的解決方法,基本概念就是dispatch queue(調度隊列),queue是一個對象,它可以接受任務,并將任務以先到先執行的順序來執行。dispatch queue可以是并發的或串行的。GCD的底層依然是用線程實現,不過我們可以不用關注實現的細節。其優點有如下幾點:

(1)易用:GCD比thread更簡單易用?;赽lock的特效使它能極為簡單地在不同代碼作用域之間傳遞上下文。

(2)效率:GCD實現功能輕量,優雅,使得它在很多地方比專門創建消耗資源的線程更加實用且快捷。

(3)性能:GCD自動根據系統負載來增減線程數量,從而減少了上下文切換并增加了計算效率。

(4)安全:無需加鎖或其他同步機制。

本文代碼已全部更新至Swift3。


3,GCD三種創建隊列的方法

(1)自己創建一個隊列

第一個參數代表隊列的名稱,可以任意起名

第二個參數代表隊列屬于串行還是并行執行任務

串行隊列一次只執行一個任務。一般用于按順序同步訪問,但我們可以創建任意數量的串行隊列,各個串行隊列之間是并發的。

并行隊列的執行順序與其加入隊列的順序相同。可以并發執行多個任務,但是執行完成的順序是隨機的。

//創建串行隊列let serial = DispatchQueue(label:"serialQueue1")

//創建并行隊列let concurrent = DispatchQueue(label:"concurrentQueue1", attributes: .concurrent)

(2)獲取系統存在的全局隊列?

Global Dispatch Queue有4個執行優先級:

.userInitiated??高

.default??正常

.utility??低

.background?非常低的優先級(這個優先級只用于不太關心完成時間的真正的后臺任務)


let globalQueue = DispatchQueue.global(qos: .default)

(3)運行在主線程的Main Dispatch Queue?

正如名稱中的Main一樣,這是在主線程里執行的隊列。因為主線程只有一個,所有這自然是串行隊列。一起跟UI有關的操作必須放在主線程中執行。

let mainQueue = DispatchQueue.main

4,添加任務到隊列的兩種方法?

(1)async異步追加Block塊(async函數不做任何等待)

DispatchQueue.global(qos: .default).async {

? ? //處理耗時操作的代碼塊...print("do work")


? ? //操作完成,調用主線程來刷新界面? ? DispatchQueue.main.async {

? ? ? ? print("main refresh")

? ? }

}

(2)sync同步追加Block塊?

同步追加Block塊,與上面相反。在追加Block結束之前,sync函數會一直等待,等待隊列前面的所有任務完成后才能執行追加的任務。

//添加同步代碼塊到global隊列//不會造成死鎖,但會一直等待代碼塊執行完畢DispatchQueue.global(qos: .default).sync {

? ? print("sync1")

}

print("end1")

//添加同步代碼塊到main隊列//會引起死鎖//因為在主線程里面添加一個任務,因為是同步,所以要等添加的任務執行完畢后才能繼續走下去。但是新添加的任務排在//隊列的末尾,要執行完成必須等前面的任務執行完成,由此又回到了第一步,程序卡死DispatchQueue.main.sync {

? ? print("sync2")

}

print("end2")

5,暫?;蛘呃^續隊列

這兩個函數是異步的,而且只在不同的blocks之間生效,對已經正在執行的任務沒有影響。

suspend()后,追加到Dispatch Queue中尚未執行的任務在此之后停止執行。

而resume()則使得這些任務能夠繼續執行。

//創建并行隊列let conQueue = DispatchQueue(label:"concurrentQueue1", attributes: .concurrent)//暫停一個隊列conQueue.suspend()//繼續隊列conQueue.resume()

6,只執行一次

過去dispatch_once中的代碼塊在應用程序里面只執行一次,無論是不是多線程。因此其可以用來實現單例模式,安全,簡潔,方便。

//往dispatch_get_global_queue隊列中添加代碼塊,只執行一次var predicate:dispatch_once_t =0dispatch_once(&predicate, { () -> Voidin//只執行一次,可用于創建單例println("work")

})

在Swift3中,dispatch_once被廢棄了,我們要替換成其他全局或者靜態變量和常量.

privatevar once1:Void = {

? ? //只執行一次print("once1")

}()

privatelazy var once2:String = {

? ? //只執行一次,可用于創建單例print("once2")

? ? return"once2"}()

7,asyncAfter?延遲調用

asyncAfter 并不是在指定時間后執行任務處理,而是在指定時間后把任務追加到queue里面。因此會有少許延遲。注意,我們不能(直接)取消我們已經提交到 asyncAfter 里的代碼。

//延時2秒執行DispatchQueue.global(qos: .default).asyncAfter(deadline: DispatchTime.now() +2.0) {

? ? print("after!")

}

如果需要取消正在等待執行的Block操作,我們可以先將這個Block封裝到DispatchWorkItem對象中,然后對其發送cancle,來取消一個正在等待執行的block。

//將要執行的操作封裝到DispatchWorkItem中let task = DispatchWorkItem { print("after!") }//延時2秒執行DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() +2, execute: task)//取消任務task.cancel()

8,多個任務全部結束后做一個全部結束的處理

async(group:):用來監視一組block對象的完成,你可以同步或異步地監視

notify():用來匯總結果,所有任務結束匯總,不阻塞當前線程

wait():等待直到所有任務執行結束,中途不能取消,阻塞當前線程

//獲取系統存在的全局隊列let queue = DispatchQueue.global(qos: .default)//定義一個grouplet group = DispatchGroup()//并發任務,順序執行queue.async(group: group) {

? ? sleep(2)

? ? print("block1")

}

queue.async(group: group) {

? ? print("block2")

}

queue.async(group: group) {

? ? print("block3")

}

//1,所有任務執行結束匯總,不阻塞當前線程group.notify(queue: .global(), execute: {

? ? print("group done")

})

//2,永久等待,直到所有任務執行結束,中途不能取消,阻塞當前線程group.wait()

print("任務全部執行完成")

9,concurrentPerform 指定次數的Block最加到隊列中

DispatchQueue.concurrentPerform函數是sync函數和Dispatch Group的關聯API。按指定的次數將指定的Block追加到指定的Dispatch Queue中,并等待全部處理執行結束。

因為concurrentPerform函數也與sync函數一樣,會等待處理結束,因此推薦在async函數中異步執行concurrentPerform函數。concurrentPerform函數可以實現高性能的循環迭代。

//獲取系統存在的全局隊列let queue = DispatchQueue.global(qos: .default)

//定義一個異步步代碼塊queue.async {

? ? //通過concurrentPerform,循環變量數組DispatchQueue.concurrentPerform(iterations:6) {(index) -> Voidin? ? ? ? print(index)

? ? }


? ? //執行完畢,主線程更新? ? DispatchQueue.main.async {

? ? ? ? print("done")

? ? }

}

10,信號,信號量

DispatchSemaphore(value: ):用于創建信號量,可以指定初始化信號量計數值,這里我們默認1.

semaphore.wait():會判斷信號量,如果為1,則往下執行。如果是0,則等待。

semaphore.signal():代表運行結束,信號量加1,有等待的任務這個時候才會繼續執行。

//獲取系統存在的全局隊列let queue = DispatchQueue.global(qos: .default)

//當并行執行的任務更新數據時,會產生數據不一樣的情況foriin1...10 {

? ? queue.async {

? ? ? ? print("\(i)")

? ? }

}

//使用信號量保證正確性//創建一個初始計數值為1的信號let semaphore = DispatchSemaphore(value:1)foriin1...10 {

? ? queue.async {

? ? ? ? //永久等待,直到Dispatch Semaphore的計數值 >= 1? ? ? ? semaphore.wait()

? ? ? ? print("\(i)")

? ? ? ? //發信號,使原來的信號計數值+1? ? ? ? semaphore.signal()

? ? }

}


原文出自:www.hangge.com轉載請保留原文鏈接:http://www.hangge.com/blog/cache/detail_745.html

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容