GCD

-GCD中的核心詞是dispatch queue。一個(gè)隊(duì)列實(shí)際上就是一系列的代碼塊,這些代碼可以在主線程或后臺(tái)線程中以同步或者異步的方式執(zhí)行。一旦隊(duì)列創(chuàng)建完成,操作系統(tǒng)就接管了這個(gè)隊(duì)列,并將其分配到任意一個(gè)核心中進(jìn)行處理。不管有多少個(gè)隊(duì)列,它們都能被系統(tǒng)正確地管理,這些都不需要開(kāi)發(fā)者進(jìn)行手動(dòng)管理。隊(duì)列遵循 FIFO 模式(先進(jìn)先出),這意味著先進(jìn)隊(duì)列的任務(wù)會(huì)先被執(zhí)行(想像在柜臺(tái)前排隊(duì)的隊(duì)伍,排在第一個(gè)的會(huì)首先被服務(wù),排在最后的就會(huì)最后被服務(wù))。

  • 另一個(gè)重要的概念就是WorkItem(任務(wù)項(xiàng))。一個(gè)任務(wù)項(xiàng)就是一個(gè)代碼塊,它可以隨同隊(duì)列的創(chuàng)建一起被創(chuàng)建,也可以被封裝起來(lái),然后在之后的代碼中進(jìn)行復(fù)用。正如你所想,任務(wù)項(xiàng)的代碼就是 dispatch queue 將會(huì)執(zhí)行的代碼。隊(duì)列中的任務(wù)項(xiàng)也是遵循 FIFO 模式。這些執(zhí)行可以是同步的,也可以是異步的。對(duì)于同步的情況下,應(yīng)用會(huì)一直堵塞當(dāng)前線程,直到這段代碼執(zhí)行完成。而當(dāng)異步執(zhí)行的時(shí)候,應(yīng)用先執(zhí)行任務(wù)項(xiàng),不等待執(zhí)行結(jié)束,立即返回。
  • 在為主隊(duì)列添加任務(wù)時(shí),無(wú)論何時(shí)都要加倍小心。這個(gè)隊(duì)列要隨時(shí)用于界面響應(yīng)以及用戶交互。并且記住一點(diǎn),所有與用戶界面相關(guān)的更新都必須在主線程執(zhí)行。如果你嘗試在后臺(tái)線程更新 UI,系統(tǒng)并不保證這個(gè)更新何時(shí)會(huì)發(fā)生,大多數(shù)情況下,這會(huì)都用戶帶來(lái)不好的體驗(yàn)。但是,所有發(fā)生在界面更新前的任務(wù)都可以在后臺(tái)線程執(zhí)行。
  • 我們不一定需要每次都創(chuàng)建自己的隊(duì)列。系統(tǒng)維護(hù)的全局隊(duì)列可以用來(lái)執(zhí)行任何我們想執(zhí)行的任務(wù)。至于隊(duì)列在哪一個(gè)線程運(yùn)行,iOS 維護(hù)了一個(gè)線程池,即一系列除主線程之外的線程,系統(tǒng)會(huì)從中挑選一至多條線程來(lái)使用(取決于你所創(chuàng)建的隊(duì)列的數(shù)據(jù),以及隊(duì)列創(chuàng)建的方式)。哪一條線程會(huì)被使用,對(duì)于開(kāi)發(fā)者來(lái)說(shuō)是未知的,而是由系統(tǒng)根據(jù)當(dāng)前的并發(fā)任務(wù),處理器的負(fù)載等情況來(lái)進(jìn)行“決定”。

Dispatch Queue

在 swift 中 dispatch queue 對(duì)應(yīng)的類為DispatchQueue ,可以使用下面方法進(jìn)行初始化

let queue = (label: String,
  qos: DispatchQoS = default,
  attributes: DispatchQueue.Attributes = default, 
  autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = default,
 target: DispatchQueue? = default)

在 Swift 3 當(dāng)中,創(chuàng)建一個(gè)dispatch queue的最簡(jiǎn)單方式:

let queue = DispatchQueue(label: "com.appcode.myqueue")

queue.sync {
      print("同步執(zhí)行")
 }
    queue.async {
      print("異步執(zhí)行")
 }

Quality Of Service (QOS) 和優(yōu)先級(jí)

  • 在使用GCDdispatch queue時(shí),我們經(jīng)常需要告訴系統(tǒng),應(yīng)用程序中的哪些任務(wù)比較重要,需要更高的優(yōu)先級(jí)去執(zhí)行。當(dāng)然,由于主隊(duì)列總是用來(lái)處理 UI 以及界面的響應(yīng),所以在主線程執(zhí)行的任務(wù)永遠(yuǎn)都有最高的優(yōu)先級(jí)。不管在哪種情況下,只要告訴系統(tǒng)必要的信息,iOS 就會(huì)根據(jù)你的需求安排好隊(duì)列的優(yōu)先級(jí)以及它們所需要的資源(比如說(shuō)所需的 CPU 執(zhí)行時(shí)間)。雖然所有的任務(wù)最終都會(huì)完成,但是,重要的區(qū)別在于哪些任務(wù)更快完成,哪些任務(wù)完成得更晚。

  • 用于指定任務(wù)重要程度以及優(yōu)先級(jí)的信息,在 GCD 中被稱為 Quality of Service (Qos)。事實(shí)上,Qos 是有幾個(gè)特定值的枚舉類型,我們可以根據(jù)需要的優(yōu)先級(jí),使用合適的 Qos 值來(lái)初始化隊(duì)列。如果沒(méi)有指定 Qos,則隊(duì)列會(huì)使用默認(rèn)優(yōu)先級(jí)進(jìn)行初始化。

/// 由低到高 優(yōu)先級(jí)
 public static let unspecified: DispatchQoS

 public static let background: DispatchQoS

 public static let utility: DispatchQoS

 public static let `default`: DispatchQoS

 public static let userInitiated: DispatchQoS

 public static let userInteractive: DispatchQoS

并發(fā)隊(duì)列


///public static let concurrent: DispatchQueue.Attributes
///public static let initiallyInactive: DispatchQueue.Attributes
///attributes 參數(shù)也可以接受另一個(gè)名為 initiallyInactive 的值。如果使用這個(gè)值,
///任務(wù)不會(huì)被自動(dòng)執(zhí)行,而是需要開(kāi)發(fā)者手動(dòng)去觸發(fā)。
let anotherQueue = DispatchQueue(label:"com.appcode.anotherQueue", 
qos: .utility, attributes: .concurrent)

  • DispatchQueue 類的 activate() 方法會(huì)讓任務(wù)開(kāi)始執(zhí)行。注意,這個(gè)隊(duì)列并沒(méi)有被指定為并發(fā)隊(duì)列,因此它們會(huì)以串行的方式執(zhí)行。
let anotherQueue = DispatchQueue(label:"com.appcode.anotherQueue",
 qos: .utility, attributes: .initiallyInactive)
anotherQueue.activate()
  • 現(xiàn)在的問(wèn)題是,我們?nèi)绾卧谥付?code>initiallyInactive 的同時(shí)將隊(duì)列指定為并發(fā)隊(duì)列?其實(shí)很簡(jiǎn)單,我們可以將兩個(gè)值放入一個(gè)數(shù)組當(dāng)中,作為attributes的參數(shù),替代原本指定的單一數(shù)值。
let anotherQueue = DispatchQueue(label:"com.appcode.anotherQueue", 
qos: .userInitiated, attributes: [.concurrent, .initiallyInactive])

延遲執(zhí)行

let delayQueue = DispatchQueue(label: "com.appcoda.delayqueue", qos: .userInitiated)

print(Date())

let additionalTime: DispatchTimeInterval = .seconds(2)
delayQueue.asyncAfter(deadline: .now() + additionalTime) {
    print(Date())
}

全局隊(duì)列和主隊(duì)列


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

DispatchQueue.main.async {
    // Do something
}

DispatchWorkItem

-DispatchWorkItem 是一個(gè)代碼塊,它可以在任意一個(gè)隊(duì)列上被調(diào)用,因此它里面的代碼可以在后臺(tái)運(yùn)行,也可以在主線程運(yùn)行。它的使用真的很簡(jiǎn)單,就是一堆可以直接調(diào)用的代碼,而不用像之前一樣每次都寫(xiě)一個(gè)代碼塊。

var value = 10
 let workItem = DispatchWorkItem {
       value += 5
 }
workItem.perform()/// 這行代碼會(huì)在主線程上面調(diào)用

///其他隊(duì)列執(zhí)行
let queue = DispatchQueue.global()
queue.async {
    workItem.perform()
}

queue.async(execute: workItem)

  • 當(dāng)一個(gè)任務(wù)項(xiàng)被調(diào)用后,你可以通知主隊(duì)列(或者任何其它你想要的隊(duì)列)
workItem.notify(queue: DispatchQueue.main) {
    print("value = ", value)
}


    var value = 10

    let workItem = DispatchWorkItem {
        value += 5
    }

    workItem.perform()

    let queue = DispatchQueue.global(qos: .utility)

    queue.async(execute: workItem)

    workItem.notify(queue: DispatchQueue.main) {
        print("value = ", value)
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • GCD(Grand Central Dispatch) 介紹 GCD 屬于系統(tǒng)級(jí)的線程管理,在 Dispatch ...
    fuyoufang閱讀 4,736評(píng)論 0 10
  • 盡管 Grand Central Dispatch (GCD)已經(jīng)存在一段時(shí)間了,但并非每個(gè)人都知道怎么使用它。這...
    coderFamer閱讀 7,448評(píng)論 1 16
  • 基于自 raywenderlich.com 在2015年的兩篇文章 Grand Central Dispatch ...
    seedante閱讀 1,401評(píng)論 0 7
  • 一、本周計(jì)劃(一)這周就要跑馬,周二進(jìn)行半馬練習(xí),每天拿出時(shí)間規(guī)劃準(zhǔn)備;(二)幸福雙翼跟上進(jìn)程,錄制音頻;、(三)...
    舜間永恒閱讀 162評(píng)論 0 1
  • 很久沒(méi)有遛彎了。 最近心情總是起起落落,心里那股子叛逆也上來(lái)了。 對(duì)啊,我就是不想考好,不想去迎合應(yīng)試教育。 我呸...
    花房姑娘__閱讀 228評(píng)論 0 0