標籤:efault patch map 影響 oid 計算 end 輕量 基本
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更簡單易用。基於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 = 0dispatch_once(&predicate, { () -> Void in //只執行一次,可用於建立單例 println("work")})
在Swift3中,dispatch_once被廢棄了,我們要替換成其他全域或者靜態變數和常量.
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)//定義一個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) -> 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
Swift - 多線程實現方式 - Grand Central Dispatch(GCD)