輕松學iOS多線程之 GCD 的基本使用

GCD 的全稱是 Grand Central Dispatch,可譯為“牛逼的中樞調度器”,GCD 是純 C 語言,提供了非常多且強大的函數。

  • GCD 的優勢
    • GCD是蘋果公司為多核的并行運算提出的解決方案
    • GCD會自動利用更多的CPU內核(比如雙核、四核)
    • GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程)
    • 程序員只需要告訴GCD想要執行什么任務,不需要編寫任何線程管理代碼

任務與隊列

在 GCD 中有兩個核心概念,分別是任務和隊列。

  • 任務:用來執行什么操作
  • 隊列:用來存放任務

使用 GCD 只需要兩個步驟:

  1. 封裝任務:
    • 確定想要做的事情
  • 將任務添加到隊列中:
    • GCD會自動將隊列中的任務取出,放到對應的線程中執行
    • 任務的取出遵循隊列的 FIFO 原則:先進先出,后進后出,即先存進去的任務優先取出執行

執行任務的兩種常用函數

  1. 同步函數

    • 只能在當前線程中執行任務,不具備開啟新線程的能力
    dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
    
  2. 異步函數

    • 可以在新的線程中執行任務,具備開啟新線程的能力
    dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
    

隊列的基本類型

  1. 并發隊列
    • 可以讓多個任務并發(同時)執行(自動開啟多個線程同時執行任務)
    • 并發功能只有在異步(dispatch_async)函數下才有效
  2. 串行隊列
    • 讓任務一個接著一個地執行(一個任務執行完畢后,再執行下一個任務)
  3. 主隊列
    • 凡是添加到主隊列中的任務一律放到主線程中執行
  4. 全局并發隊列
    • 在系統中默認就存在了四種優先級的全局并發隊列
      • DISPATCH_QUEUE_PRIORITY_HIGH // 高
      • DISPATCH_QUEUE_PRIORITY_DEFAULT // 默認(中)
      • DISPATCH_QUEUE_PRIORITY_LOW // 低
      • DISPATCH_QUEUE_PRIORITY_BACKGROUND // 后臺

注意:同步和異步主要影響的是能不能開啟新的線程,并發和串行主要影響的是任務的執行方式,這里千萬不要混淆了。

GCD 的六種基本使用方式

在 iOS6.0 之前,在 GCD 中每當使用帶 creat 單詞的函數創建對象之后,都應該對其進行一次 release 操作。在 iOS6.0 之后,GCD 被納入到了 ARC 的內存管理機制,就不再關心內存問題了。

  1. 同步函數 + 串行隊列

    • 不會開線程,所有的任務在當前線程串行執行
    /**
      "syncSerial"    隊列的名稱,調試的時候使用
      DISPATCH_QUEUE_CONCURRENT     并發隊列
      DISPATCH_QUEUE_SERIAL         串行隊列
     */
     dispatch_queue_t queue = dispatch_queue_create("syncSerial", DISPATCH_QUEUE_SERIAL);    
     dispatch_sync(queue, ^{
        NSLog(@"--- %@", [NSThread currentThread]);
    });
    
  2. 同步函數 + 并發隊列

    • 不會開線程,所有的任務在當前線程串行執行
    dispatch_queue_t queue = dispatch_queue_create("syncConcurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"--- %@", [NSThread currentThread]);
    });
    
  3. 同步函數 + 主隊列

    • 產生死鎖
    • 原因:同步函數不會新開線程,必須在當前線程(主線程)執行完本次任務才能繼續向下執行,但是主隊列中的任務必須在主線程中執行,就會去調用主線程來執行任務,這樣就會形成主線程要執行任務,任務要調用主線程的情況,形成死循環,即形成死鎖。
    //獲取主隊列
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"--- %@", [NSThread currentThread]);
    });
    
  4. 異步函數 + 串行隊列

    • 會開一條線程,所有的任務在當前線程串行執行
    dispatch_queue_t queue = dispatch_queue_create("asyncSerial",     DISPATCH_QUEUE_SERIAL);    
    dispatch_async(queue, ^{
        NSLog(@"--- %@", [NSThread currentThread]);
    });
    
  5. 異步函數 + 并發隊列

    • 會開多條線程(至少一條,具體由系統決定,與任務的數量無關),所有的任務并發執行
    dispatch_queue_t queue = dispatch_queue_create("asyncConcurrent", DISPATCH_QUEUE_CONCURRENT);
    //將任務添加到隊列中
    dispatch_async(queue, ^{
        NSLog(@"--- %@", [NSThread currentThread]);
    });
    
  6. 異步函數 + 主隊列

    • 不會開線程,所有的任務在主線程中串行執行
    //獲取主隊列
    dispatch_queue_t queue = dispatch_get_main_queue();    
    dispatch_async(queue, ^{
        NSLog(@"--- %@", [NSThread currentThread]);
    });
    

隊列的執行效果

并發隊列 手動創建的串行隊列 主隊列
同步( sync ) 沒有開啟新線程,當前線程串行執行任務 沒有開啟新線程,當前線程串行執行任務 死鎖
異步( async ) 開啟多條新線程,并發執行任務 開啟一條新線程,串行執行任務 沒有開啟新線程,主線程串行執行任務

注意:使用同步函數往當前串行隊列中添加任務,會卡住當前的串行隊列。

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

推薦閱讀更多精彩內容