Swift3.0 GCD多線程詳解

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?GCD思維導圖

GCD(Grand Central Dispatch)是蘋果公司實現的一套先進先出執行的任務隊列, 我們只要將程序閉包傳給GCD, mac os會在系統線程池里執行該任務, 而且無法確定到底是哪個線程執行的。 總之, GCD是個順序或并發執行隊列, 封裝了線程的調度, 開發者不用直接操作線程了。

DispatchQueue支持同步sync和異步async方法,每個人物即DispatchWorkItem只執行一遍; 同步和并發方法都是按照先進先出的順序執行隊列里的任務。

App進程在啟動時系統會自動創建一個main queue即DispatchQueue.main, 注意該queue里不能執行耗時操作并只能在main隊列里刷新界面。

1、DispatchQueue基本用法異步async:在子線程執行耗時操作完成后,將結果刷新到界面; 注意放開注釋使用實例化queue和global的效果是一樣的。

//let queue = DispatchQueue(label: "com.brycegao.gcdtest")

DispatchQueue.global().async {

//queue.async {

let url = URL(string: "http://img-arch.pconline.com.cn/images/upload/upc/tx/photoblog/1107/05/c5/8235345_8235345_1309860279806.jpg")!

if let imageData = try? Data(contentsOf: url) {? //從網上取數據,屬于耗時操作

let tmpimage = UIImage(data: imageData as Data)? //二進制數據轉換為圖片,屬于耗時操作

DispatchQueue.main.async {? //通知ui刷新

self.image = tmpimage

self.imageView.image = self.image

}

}

}

這段代碼的作用從網上下載一張圖片并顯示在UIImageView, 注釋值傳遞! 根據閉包的語法特性, 閉包內可以訪問外部的變量, 例如DispatchQueue.main.async閉包內能夠使用外部變量self。

let queue = DispatchQueue(label: "com.brycegao.gcdtest")

queue.async {

let date = Date()

print("async1 \(date.description)")

Thread.sleep(forTimeInterval: 1)? //停止1秒

}

queue.async {

let date = Date()

print("async2 \(date.description)")

Thread.sleep(forTimeInterval: 1)

}

queue.async {

let date = Date()

print("async3 \(date.description)")

Thread.sleep(forTimeInterval: 1)

}

從日志可以看出FIFO的特點,先添加的任務肯定先執行

async1 2016-12-27 13:47:38 +0000

async2 2016-12-27 13:47:39 +0000

async3 2016-12-27 13:47:40 +0000

2、DispatchQueue基本用法同步sync, 該方法會阻塞UI隊列, 導致不顯示控件或無點擊事件等問題; sync方法仍然按照FIFO順序執行。

let queue = DispatchQueue(label: "com.brycegao.gcdtest")

queue.async {? //異步方法不阻塞UI

let date = Date()

print("async1 \(date.description)")

Thread.sleep(forTimeInterval: 1)? //停止1秒

}

queue.sync {? //同步方法會阻塞UI,造成不顯示控件或無點擊事件,但仍然是順序執行

let date = Date()

print("sync \(date.description)")

Thread.sleep(forTimeInterval: 10)

}

queue.async {

let date = Date()

print("async3 \(date.description)")

Thread.sleep(forTimeInterval: 1)

}

async1 2016-12-27 13:55:17 +0000

sync 2016-12-27 13:55:18 +0000

async3 2016-12-27 13:55:28 +0000

3、DispatchQos用于描述隊列優先級, 從高到低分為userInteractive,userInitiated,default,utility,background, 默認是default。

4、上面介紹的是串行隊列(默認), 現在介紹并行隊列。 并行對列只能通過實例化方式得到, 區別是有.concurrent參數。將上面的示例代碼稍作改動, 即修改DispatchQueue的實例化方法參數。

let conqueue = DispatchQueue(label: "queuename", attributes: .concurrent)? //并發隊列

conqueue.async {

let date = Date()

print("async1 \(date.description)")

Thread.sleep(forTimeInterval: 1)? //停止1秒

}

conqueue.async {? //同步方法會阻塞UI,造成不顯示控件或無點擊事件,但仍然是順序執行

let date = Date()

print("async2 \(date.description)")

Thread.sleep(forTimeInterval: 1)

}

conqueue.async {

let date = Date()

print("async3 \(date.description)")

Thread.sleep(forTimeInterval: 1)

}? ? ? ? /*DispatchQueue.global().async

從日志看跟普通的多線程并發是一樣的, 在這里是在mac os線程池內執行的。

async1 2016-12-27 14:08:21 +0000

async2 2016-12-27 14:08:21 +0000

async3 2016-12-27 14:08:21 +0000

5、設置運行時間asyncAfter函數可以設置延遲一段時間后運行閉包,功能類似于定時器。 還是在上面示例代碼上稍作修改。

.....

conqueue.async {

let date = Date()

print("async1 \(date.description)")

Thread.sleep(forTimeInterval: 1)? //停止1秒

}

let time = DispatchTime.now() + 3

conqueue.asyncAfter(deadline: time, execute: {

let date = Date()

print("asyncAfter \(date.description)")

})

....

輸出:

async1 2016-12-27 14:16:11 +0000

async3 2016-12-27 14:16:11 +0000

async2 2016-12-27 14:16:11 +0000

asyncAfter 2016-12-27 14:16:14 +0000

6、DispatchGroup的作用就是監聽一個或多個DispatchQueue任務結束的觸發事件, 類似于Java的wait/notifyAll。

let group = DispatchGroup()

let queue1 = DispatchQueue(label: "queue1")

queue1.async(group: group) {

Thread.sleep(forTimeInterval: 1)? //停止1秒

let date = Date()

print("async1 \(date.description)")

}

let queue2 = DispatchQueue(label: "queue2")

queue2.async(group: group) {

Thread.sleep(forTimeInterval: 3)

let date = Date()

print("asycn2 \(date.description)")

}

let queue3 = DispatchQueue(label: "queue3")

queue3.async(group: group){

Thread.sleep(forTimeInterval: 1)

let date = Date()

print("async3 \(date.description)")

}

let date1 = Date()

print("date1: \(date1.description)")

group.wait()? ? //等待group的任務都執行完成后向下執行

let date2 = Date()

print("date2: \(date2.description)")

日志:

date1: 2016-12-27 14:32:52 +0000

async3 2016-12-27 14:32:53 +0000

async1 2016-12-27 14:32:53 +0000

asycn2 2016-12-27 14:32:55 +0000

date2: 2016-12-27 14:32:55 +0000

如上面示例代碼, 將3個DispatchQueue的任務添加到DispatchGroup中,? date1先打印出來, 等到async1、async2、async3都執行完成后才打印date2。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 1. 前言 之前寫了一遍文章介紹了Objective-C中GCD的用法: [iOS]多線程--GCD, 現在轉戰到...
    流火緋瞳閱讀 3,692評論 0 6
  • 在這篇文章中,我將為你整理一下 iOS 開發中幾種多線程方案,以及其使用方法和注意事項。當然也會給出幾種多線程的案...
    張戰威ican閱讀 616評論 0 0
  • 【Xcode-Men】Hi,我們團隊的井小二童鞋給我們取了個隊名:Xcode-Men,簡稱X-Men,是不是屌屌的...
    知識小集閱讀 5,957評論 20 41
  • 一、前言 本篇博文介紹的是iOS中常用的幾個多線程技術: NSThread GCD NSOperation 由于a...
    和玨貓閱讀 588評論 0 1