iOS中GCD學(xué)習(xí)筆記

1. iOS中多線程的四種方案

iOS中實現(xiàn)多線程目前有4種方案,最常用的是GCD和NSOperation兩種,而本文主要介紹GCD概念和使用方法。


iOS中多線程的四種方案

2. Grand Central Dispatch(GCD)基本概念

GCD是蘋果對多核的并行運行一種解決方案。
優(yōu)點:基于C語言,簡單易用,效率高,速度快,會自動管理線程生命周期,開發(fā)者只需關(guān)心GCD要執(zhí)行的任務(wù)和隊列。
缺點: 當(dāng)GCD的場景復(fù)雜時,可能會遇到死鎖。

3. GCD術(shù)語

任務(wù)和隊列

任務(wù):執(zhí)行什么操作,在GCD中就是一個Block。
隊列:用來存放任務(wù),總共有兩種隊列,串行隊列并行隊列,遵循FIFO規(guī)則。

同步和異步

同步:會阻塞當(dāng)前線程去執(zhí)行線程內(nèi)的任務(wù),不具備開啟新線程的能力
函數(shù):dispatch_sync(dispatch_queue_t queue,dispatch_block_t block);
異步:不會阻塞當(dāng)前線程,可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力
函數(shù):dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

串行和并發(fā)

串行:一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù)
并發(fā):允許多個任務(wù)同時執(zhí)行

4. Dispatch Queue

隊列的類型有三種,分別是串行隊列并行隊列主隊列(主隊列本身是串行隊列)。

名稱 Dispatch Queue 的種類 說明
Main Dispatch Queue Serial Dispatch Queue 主線程執(zhí)行
Global Dispatch Queue (HIGH) Concurrent Dispatch Queue 執(zhí)行優(yōu)先級:高
Global Dispatch Queue (DEFAULT) Concurrent Dispatch Queue 執(zhí)行優(yōu)先級:默認(rèn)
Global Dispatch Queue (LOW) Concurrent Dispatch Queue 執(zhí)行優(yōu)先級:低
Global Dispatch Queue (BACKGROUND) Concurrent Dispatch Queue 執(zhí)行優(yōu)先級:后臺

5. 創(chuàng)建和管理隊列

  • 主隊列:是一個特殊的串行隊列,在主線程中運行,用于刷新UI。一般比較耗時的任務(wù)都會放在其他線程中運行。
//串行隊列
dispatch_queue_t queue = dispatch_get_main_queue;
  • 自定義創(chuàng)建隊列: 既可以創(chuàng)建串行隊列也可以創(chuàng)建并行隊列。
//串行隊列
  dispatch_queue_t queue = dispatch_queue_create("com.leon.testQueue", NULL);
  dispatch_queue_t queue = dispatch_queue_create("tcom.leon.testQueue", DISPATCH_QUEUE_SERIAL);
  //并行隊列
  dispatch_queue_t queue = dispatch_queue_create("com.leon.testQueue", DISPATCH_QUEUE_CONCURRENT);
  • 全局并行隊列:系統(tǒng)提供的并行隊列
//并行隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

6. 把任務(wù)添加到隊列中

  • 同步任務(wù)
dispatch_sync(<#queue#>, ^{
      //Task
      NSLog(@"Do some work here.");
  });
  • 異步任務(wù)
dispatch_async(<#queue#>, ^{
      //Task
      NSLog(@"Do some work here.");
  });

7. 案例與分析

問題1:在主線程中調(diào)用,以下代碼結(jié)果是什么?

    NSLog(@"1"); //任務(wù)1
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2"); //任務(wù)2
    });
    NSLog(@"3"); //任務(wù)3

控制臺輸出

1

結(jié)果分析

  1. dispatch_sync表示是一個同步線程,會阻塞當(dāng)前線程,然后把Block中任務(wù)添加到隊列中執(zhí)行,等到Block中任務(wù)完成后才會讓當(dāng)前線程繼續(xù)執(zhí)行。
  2. dispatch_get_main_queue表示主線程中的主隊列;

首先執(zhí)行任務(wù)1,打印出1,程序遇到dispatch_sync會立即阻塞當(dāng)前主線程,把任務(wù)2放到主隊列中, 等待任務(wù)2執(zhí)行完,再執(zhí)行任務(wù)3??墒侵麝犃惺前凑誇IFO原則執(zhí)行任務(wù),此時主隊列中任務(wù)3排在任務(wù)2之前,所以要等到任務(wù)3執(zhí)行完后才能執(zhí)行任務(wù)2,這就會造成他們進入互相等待的局面,從而產(chǎn)生死鎖。避免死鎖的方法是在使用dispatch_sync執(zhí)行任務(wù)時,傳入?yún)?shù)的隊列不要和當(dāng)前線程的隊列是一樣的。

問題2:以下代碼的輸出結(jié)果是什么?

 dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); //任務(wù)1
    dispatch_async(queue, ^{
        NSLog(@"2"); //任務(wù)2
        dispatch_sync(queue, ^{
            NSLog(@"3"); //任務(wù)3
        });
        NSLog(@"4"); //任務(wù)4
    });
    NSLog(@"5"); //任務(wù)5

控制臺輸出

1
5
2
5和2的順序不一定

結(jié)果分析

  1. 首先自定義創(chuàng)建了一個串行隊列(DISPATCH_QUEUE_SERIAL)。
  2. 執(zhí)行任務(wù)1,打印出1。
  3. dispatch_async 是異步執(zhí)行,所以當(dāng)前線程不會被阻塞,會另外開啟一個新線程,于是當(dāng)前有兩個線程在運行,管他們叫主線程和輔線程。
  4. 主線程繼續(xù)執(zhí)行任務(wù)5,打印出5。
  5. 輔線程執(zhí)行Block中的任務(wù)。而Block中的任務(wù)和上一個例子問題1是一樣的??梢园凑丈蟼€例子方法分析,只會執(zhí)行任務(wù)2,打印出2。由于主線程和輔線程是異步執(zhí)行的,所以5和2沒有先后順序。

8. GCD其他一些特性

  • 循環(huán)執(zhí)行任務(wù)
    dispatch_apply類似一個for循環(huán),并發(fā)的執(zhí)行每一項。所有任務(wù)結(jié)束后,dispatch_apply才會返回,會阻塞當(dāng)前線程。如果傳入隊列是串行隊列,要注意防止死鎖現(xiàn)象的發(fā)生。
//循環(huán)執(zhí)行任務(wù),任務(wù)的順序是無序列的并且會堵塞當(dāng)前的線程。
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // count: 循環(huán)執(zhí)行次數(shù)
    // queue: 隊列,可以是串行隊列或者是并行隊列
    // block: 任務(wù)
    dispatch_apply(count, queue, ^(size_t i) {
        NSLog(@"%zu %@", i, [NSThread currentThread]);
    });
  • 隊列組
    隊列組將很多隊列添加到一個組里,當(dāng)組里所有任務(wù)都執(zhí)行完后,它會通過一個方法通知我們?;玖鞒淌鞘紫葎?chuàng)建一個隊列組,然后把任務(wù)添加到組中,最后等待隊列組的執(zhí)行結(jié)果。
//創(chuàng)建隊列組
    dispatch_group_t group = dispatch_group_create();
    //創(chuàng)建隊列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //將執(zhí)行任務(wù)添加到隊列組中, 隊列組只有異步方法能添加任務(wù)
    //執(zhí)行3次循環(huán)
    dispatch_group_async(group, queue, ^{
        for (NSInteger i = 0; i < 3; i++) {
            NSLog(@"group-01 - %@", [NSThread currentThread]);
        }
    });
    
    //主隊列執(zhí)行8次循環(huán)
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"group-02 - %@", [NSThread currentThread]);
        }
    });
    
    //都完成后會自動通知
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"完成 - %@", [NSThread currentThread]);
    });
  • dispatch_once_t實現(xiàn)單例模式
static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //dispatch_once中的代碼只執(zhí)行一次,常用來實現(xiàn)單例
        //創(chuàng)建實例變量

    });
  • GCD延遲操作
//創(chuàng)建隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//設(shè)置延時,單位秒
double delay = 3; 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{
    //3秒后需要執(zhí)行的任務(wù)
});

參考資料:
1.章魚哥的iOS多線程相關(guān)學(xué)習(xí)筆記
2.GCD
3.iOS中GCD的使用小結(jié)
4.iOS多線程GCD簡介
5.GCD介紹
6.GCD基礎(chǔ)知識集合
7.關(guān)于iOS多線程,你看我就夠了
8.Concurrency Programming Guide

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本篇博客共分以下幾個模塊來介紹GCD的相關(guān)內(nèi)容: 多線程相關(guān)概念 多線程編程技術(shù)的優(yōu)缺點比較? GCD中的三種隊列...
    dullgrass閱讀 38,128評論 28 236
  • iOS中GCD的使用小結(jié) 作者dullgrass 2015.11.20 09:41*字?jǐn)?shù) 4996閱讀 20199...
    DanDanC閱讀 1,324評論 0 0
  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,408評論 21 42
  • GCD筆記 總結(jié)一下多線程部分,最強大的無疑是GCD,那么先從這一塊部分講起. Dispatch Queue的種類...
    jins_1990閱讀 840評論 0 1
  • 簡介 GCD(Grand Central Dispatch)是在macOS10.6提出來的,后來在iOS4.0被引...
    sunmumu1222閱讀 960評論 0 2

友情鏈接更多精彩內(nèi)容