日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GCD深入学习之GCD的初识

發布時間:2023/12/18 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GCD深入学习之GCD的初识 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

如果移動端訪問不佳,可以訪問我的個人博客

現在網上關于GCD的介紹已經很多了,在項目中也經常用到,但是沒怎么深入研究過,打算寫一系列關于GCD使用,參考其他大神寫的博客和Apple的技術文檔總結一下,一是自己深入學習一下,二是以后忘了可以回過頭來溫習一下~

什么是GCD?

GCD全名是Grand Central Dispatch(大中央調度器),是系統級的,存在于libdispatch.dylib這個庫里,是Apple開發的一個多核編程的解決方法,它提供了一下幾種好處:

  • GCD用純C編寫,可以提高應用程序的響應能力,更加高效;
  • GCD使用簡單,會自動利用更多的CPU內核(比如雙核、四核),自動管理線程的生命周期(創建線程、調度任務、銷毀線程),程序員只需要告訴GCD想要執行什么任務,不需要編寫任何線程管理代碼,提供更容易并發模型,有助于避免并發錯誤。

GCD的相關術語

要了解GCD,你必須熟悉相關的線程和并發的幾個概念。這些既可以是模糊的,微妙的,所以花點時間在GCD的背景下簡要回顧一下他們。

串行和并發

在執行任務時,串行是任務順序執行,執行完一個下一個。并發就是任務可能同時執行多個任務。在GCD中一個任務就是一個閉包,這比NSOperation中的任務更加容易理解。

同步和異步

在計算機領域,同步就是指一個進程在執行某個請求的時候,若該請求需要一段時間才能返回信息,那么這個進程將會一直等待下去,直到收到返回信息才繼續執行下去;異步是指進程不需要一直等下去,而是繼續執行下面的操作,不管其他進程的狀態。當有消息返回時系統會通知進程進行處理,這樣可以提高執行的效率。

臨界區

通過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問。在任意時刻只允許一個線程對共享資源進行訪問,如果有多個線程試圖訪問公共資 源,那么在有一個線程進入后,其他試圖訪問公共資源的線程將被掛起,并一直等到進入臨界區的線程離開,臨界區在被釋放后,其他線程才可以搶占。

死鎖

是指兩個或兩個以上的進程在執行過程中,由于競爭資源或者由于彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程,簡單來說就是A線程在等待B線程完成后執行,B線程也在等待A線程完成后執行,這樣就出現了死鎖的現象。

線程安全

線程安全的代碼可以從多個線程或并發任務安全地調用,而不會造成任何問題(數據損壞,系統崩潰等)。例如當你多線程編程時,你用let定義一個數組,因為它是只讀的,你能在同一時間不同線程去使用它,而不會造成線程安全的問題,然而當你用var定義一個數組時就不一樣了,它不是線程安全的,當多個線程在同一時間訪問和修改數組時會產生不可預知的結果。

上下文切換

上下文切換是存儲和恢復執行的狀態,是你在一個進程中執行不同的線程之間切換的過程。這個過程是編寫多任務處理應用程序時很常見,但也帶來了一些額外的開銷成本。就像并發就是通過切換上下文來實現的。

并發和并行

在多核設備上執行任務時,每個CPU可以單獨工作,每個CPU同時執行不同的任務,這就是并行,然而為了使單核的設備實現這種效果達到類似的效果,因為它們只有一個線程,它們只能通過快速的上下文切換來達到并行的假象,這就是并發,如下圖所示:

GCD隊列

GCD用dispatch queues來處理提交的任務,隊列用FIFO(先進先出)的原理來管理這些任務,所有的dispatch queues本身是線程安全的,你可以從多個線程去訪問它們,在GCD 中提供了兩種隊列,分別是串行隊列和并發隊列。

串行隊列

串行隊列保證同一時間隊列里只有一個任務在執行,只有等待第一個任務執行完成后才會執行下一個任務,你也不知道兩個任務之間的間隔時間是多少,如下圖所示:

使用串行隊列有一下的優點:

  • 能確保對一個共享資源進行串行化的訪問,避免了數據競爭;
  • 任務的執行順序是可預知的,你向一個串行隊列提交任務時,它們被執行的順 序與它們被提交的順序相同;
  • 并發隊列

    并發隊列可以讓你并行的執行多個任務。任務按照它們被加入到隊列中的順序依次開始,但是它們都是并發的被執行,并不需要彼此等待才開始。并發隊列能保證任務按同一順序開始,但你不能知道執行的順序、執行的時間以及在某一時刻正在被執行任務的數量,具體如下圖所示:

    GCD 的隊列類型

    在使用過程中系統會自動給每個應用提供一個串行隊列和四個并發隊列,其中串行隊列為全局可用的串行隊列,在應用的主線程中執行任務且只有一個,這個隊列被用來更新 App 的 UI,執行所有與更新 UIViews 相關的任務。該隊列中同一時刻只執行一個任務,這就是為什么當你在主隊列中運行一個繁重的任務時UI會被阻塞的原因。GCD提供了一下三種隊列:

    • 主隊列:任務以串行的方式執行在您的應用程序的主線程;
    • 并發隊列:任務在先進先出的順序列中移除,但并發運行,可以按照任何順序完成;
    • 串行隊列:以先進先出順序執行一次任務。

    除主隊列之外,系統還提供了4個并發隊列。我們管它們叫 Global Dispatch queues(全局派發隊列)。這些隊列對整個應用來說是全局可用的,彼此只有優先級高低的區別。要使用其中一個全局并發隊列的話,你得使用 dispatch_get_global_queue 函數獲得一個你想要的隊列的引用,該函數的第一個參數取如下值:

    • DISPATCH_QUEUE_PRIORITY_HIGH:高優先級的隊列,高于其他任務優先級的隊列。

    • DISPATCH_QUEUE_PRIORITY_DEFAULT:默認優先級隊列,高于下面兩個優先級,

    • DISPATCH_QUEUE_PRIORITY_LOW:低優先級隊列,低于上面兩個優先級。
    • DISPATCH_QUEUE_PRIORITY_BACKGROUND:最低的優先級,使用它可以盡可能的減少對系統的影響。

    你可以創建任何數量的串行或并發隊列。使用并發隊列的情況下,即使你可以自己創建,但是還是強烈建議你使用上面那四個全局隊列,避免帶來沒必要的麻煩。

    創建和管理GCD隊列

    dispatch_get_main_queue() -> dispatch_queue_t!

    返回值

    通過這個函數來獲取主線程隊列:

    //返回主線程隊列 dispatch_get_main_queue()

    dispatch_get_global_queue(identifier: Int, _ flags: UInt) -> dispatch_queue_t!

    返回值

    通過這個函數來獲取系統提供的4個并發隊列

    參數列表

    參數名參數描述
    identifier代表的隊列的優先級,為DISPATCH_QUEUE_PRIORITY_HIGH、DISPATCH_QUEUE_PRIORITY_DEFAULT、DISPATCH_QUEUE_PRIORITY_LOW、DISPATCH_QUEUE_PRIORITY_BACKGROUND中的一個
    flags蘋果官方解釋是保留已提供將來使用,目前讓這個參數為0
    //返回DISPATCH_QUEUE_PRIORITY_HIGH優先級的隊列 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) //返回DISPATCH_QUEUE_PRIORITY_DEFAULT優先級的隊列 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) //返回DISPATCH_QUEUE_PRIORITY_LOW優先級的隊列 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0) //返回DISPATCH_QUEUE_PRIORITY_BACKGROUND優先級的隊列 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)

    dispatch_queue_create(label: UnsafePointer, _ attr: dispatch_queue_attr_t!) -> dispatch_queue_t!

    返回值

    通過這函數來創建一個新的隊列。

    參數列表

    參數參數描述
    label為你創建的隊列的標簽,建議用反向DNS的命名風格(com.example.myqueue),這個參數是可選的,可以為NULL。
    attrGCD隊列的屬性,這個參數來選擇創建的是串行隊列(DISPATCH_QUEUE_SERIAL)還是并發隊列(DISPATCH_QUEUE_CONCURRENT)和隊列的優先級別。
    //創建一個標識為com.wcl.www的并發隊列 dispatch_queue_create("com.wcl.www", DISPATCH_QUEUE_CONCURRENT) //創建一個標識為com.imwcl.www的串行隊列 dispatch_queue_create("com.imwcl.www", DISPATCH_QUEUE_SERIAL)

    dispatch_get_current_queue()

    返回值

    返回當前任務中的隊列。

    dispatch_queue_attr_make_with_qos_class(attr: dispatch_queue_attr_t!, _ qos_class: dispatch_qos_class_t, _ relative_priority: Int32) -> dispatch_queue_attr_t!

    返回值

    返回一個適用于創建一個想要的服務質量信息的GCD隊列的屬性。主要用于dispatch_queue_create函數。

    參數列表

    參數參數描述
    attrGCD隊列的屬性,這個參數來選擇創建的是串行隊列(DISPATCH_QUEUE_SERIAL)還是并發隊列(DISPATCH_QUEUE_CONCURRENT)和隊列的優先級別。
    qos_class這個參數為隊列優先級,同樣為DISPATCH_QUEUE_PRIORITY_HIGH、DISPATCH_QUEUE_PRIORITY_DEFAULT、DISPATCH_QUEUE_PRIORITY_LOW、DISPATCH_QUEUE_PRIORITY_BACKGROUND中的一個。
    relative_priority這個參數為QOS類中相對優先級,這個值必須小于0,大于QOS_MIN_RELATIVE_PRIORITY,根據log數據發現QOS_MIN_RELATIVE_PRIORITY的值為-15,那說明第二個參數的值在0~-15之間。

    第三個參數為QOS類中相對優先級,也就是第二個參數的類,這個值必須小于0,大于QOS_MIN_RELATIVE_PRIORITY。

    global queue優先級映射到以下quality-of-service類:

    • DISPATCH_QUEUE_PRIORITY_HIG映射到QOS_CLASS_USER_INITIATED。
    • DISPATCH_QUEUE_PRIORITY_DEFAULT映射到QOS_CLASS_DEFAULT
    • DISPATCH_QUEUE_PRIORITY_LOW映射到QOS_CLASS_UTILITY
    • DISPATCH_QUEUE_PRIORITY_BACKGROUND映射到QOS_CLASS_BACKGROUND
    let att = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, QOS_MIN_RELATIVE_PRIORITY) //根據att來創建一個隊列 dispatch_queue_create("com.wcl.www", att)

    dispatch_queue_get_label(dispatch_queue_t queue)

    返回值

    返回已經創建隊列的指定標簽。如果隊列在創建過程中沒有提供標簽,則可能返回NULL。

    //返回隊列的標簽 dispatch_queue_get_label(dispatch_get_main_queue())

    dispatch_main( void)

    執行主隊列上被提交的所有block。這個函數是為主線程而存在的并且等待執行提交到主隊列中的block。在主線程中調用了UIApplicationMain(iOS) ,NSApplicationMain(OS X),或者CFrunLoopRun的應用程序一定不要調用dispatch_main。

    int main(int argc, const charchar * argv[]) { @autoreleasepool { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"等待1。。。。"); }); dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"等待1。。。。"); }); dispatch_main(); } return 0; }

    如上:如果不調用dispatch_main()函數,則不會打印出結果。

    dispatch_set_target_queue(object: dispatch_object_t!, _ queue: dispatch_queue_t!)

    參數列表

    參數參數描述
    object要修改的對象,該參數不能為空。
    queue處理這個對象的目標隊列,這個參數不能為NULL

    給GCD對象設置目標隊列,這個目標隊列負責處理這個對象。處理的對象分別有一下幾種:

    • GCD隊列:dispatch_queue_t,一個GCD隊列的優先級是繼承自它的目標隊列的。使用dispatch_get_global_queue函數去獲得一個合適的目標隊列,這個目標隊列就是你所需的優先級。

      如果你提交一個block到一個串行隊列中,并且這個串行隊列的目標隊列是一個不同的串行隊列,那么這個block將不會與其他被提交到這個目標隊列的block或者任何其他有相同目標隊列的隊列同時調用。

    • GCD數據源:dispatch_source_t,為一個GCD數據源的目標隊列指定了它的事件處理者的block和取消事件處理的block。

    • GCD I/O通道:dispatch_io_t,一個GCD I/O通道的目標隊列指定了被執行的I/O操作。這可能會影響I/O操作結果的優先級。例如,如果這個通道的目標隊列的優先級被設置為DISPATCH_QUEUE_PRIORITY_BACKGROUND,那么當有I/O操作爭奪的時候,任何在這個隊列上通過dispatch_io_read或dispatch_io_write執行的I/O操作都會被壓制。

    關于dispatch_source_t和dispatch_io_t的用法會在以后的章節去介紹。

    總結:這篇文章主要詳細的介紹了一下關于多線程的知識和GCD隊列的的創建,關于GCD的用法和其他方面的知識會在后續文章里面去描述,給自己立一個flag,爭取完全弄懂以后寫出好的博客來。

    參考文檔

    蘋果官方GCD參考文檔

    國外一篇好的關于GCD的文檔

    總結

    以上是生活随笔為你收集整理的GCD深入学习之GCD的初识的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。