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)html

GCD是Apple開發的一個多核編程的解決方法,基本概念就是dispatch queue(調度隊列),queue是一個對象,它能夠接受任務,並將任務以先到先執行的順序來執行。dispatch queue能夠是併發的或串行的。GCD的底層依然是用線程實現,不過咱們能夠不用關注實現的細節。其優勢有以下幾點:
(1)易用:GCD比thread更簡單易用。基於block的特效使它能極爲簡單地在不一樣代碼做用域之間傳遞上下文。
(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 = 0
dispatch_once(&predicate, { () -> Void in
    //只執行一次,可用於建立單例
    println("work")
})

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

private var once1:Void = {
    //只執行一次
    print("once1")
}()
 
private lazy 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)
//定義一個group
let 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) -> Void in
        print(index)
    }
     
    //執行完畢,主線程更新
    DispatchQueue.main.async {
        print("done")
    }
}

10,信號,信號量

DispatchSemaphore(value: ):用於建立信號量,能夠指定初始化信號量計數值,這裏咱們默認1.
semaphore.wait():會判斷信號量,若是爲1,則往下執行。若是是0,則等待。
semaphore.signal():表明運行結束,信號量加1,有等待的任務這個時候纔會繼續執行。
//獲取系統存在的全局隊列
let queue = DispatchQueue.global(qos: .default)
 
//當並行執行的任務更新數據時,會產生數據不同的狀況
for i in 1...10 {
    queue.async {
        print("\(i)")
    }
}
 
//使用信號量保證正確性
//建立一個初始計數值爲1的信號
let semaphore = DispatchSemaphore(value: 1)
for i in 1...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

相關文章
相關標籤/搜索