GCD

目錄

  • 知識點概況
  • 隊列和任務(wù)
  • 并發(fā)和并行
  • 常用場景

知識點
什么是GCD?以下摘自蘋果的官方說明
Grand Central Dispatch (GCD)是異步執(zhí)行任務(wù)的技術(shù)之一,一般將應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)級實現(xiàn)。開發(fā)者只需要定義想執(zhí)行的任務(wù)并追加到適當?shù)腄ispatch Queue中,GCD就能生成必要的線程并計劃執(zhí)行任務(wù)。由于線程管理是作為系統(tǒng)的一部分實現(xiàn)的,因此可統(tǒng)一管理,也可執(zhí)行任務(wù),這樣就比以前的線程更有效率。

GCD中有2個核心概念:

1. 任務(wù)和隊列

  • 任務(wù):執(zhí)行什么操作,任務(wù)有兩種執(zhí)行方式: 同步函數(shù) 和 異步函數(shù),他們之間的區(qū)別是

    • 同步:只能在當前線程中執(zhí)行任務(wù),不具備開啟新線程的能力,任務(wù)立刻馬上執(zhí)行,會阻塞當前線程并等待 Block中的任務(wù)執(zhí)行完畢,然后當前線程才會繼續(xù)往下運行
    • 異步:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力,但不一定會開新線程,當前線程會直接往下執(zhí)行,不會阻塞當前線程
  • 隊列:用來存放任務(wù),分為串行隊列 和 并行隊列

    • 串行隊列(Serial Dispatch Queue)
      讓任務(wù)一個接著一個地執(zhí)行(一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù))
    • 并行隊列(Concurrent Dispatch Queue)
      可以讓多個任務(wù)并行(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù))

2. 并發(fā)和并行的區(qū)別

(并發(fā)和并行的區(qū)別:并發(fā)是同一時間內(nèi)執(zhí)行多個任務(wù),并行是同一時刻執(zhí)行多個任務(wù)!)
* 并發(fā):一個處理器同時處理多個任務(wù)。
* 并行:多個處理器或者是多核的處理器同時處理多個不同的任務(wù).

前者是邏輯上的同時發(fā)生(simultaneous),而后者是物理上的同時發(fā)生.


image.png

3. GCD API 常用場景

  • 應(yīng)用場景1:等待現(xiàn)在執(zhí)行中處理結(jié)束,多任務(wù)則按順序進行-> serialQueue() <對應(yīng)Demo中函數(shù)>

  • 應(yīng)用場景2:不等待現(xiàn)在執(zhí)行中處理結(jié)束,多任務(wù)并行進行。適用于耗時操作,沒有前后邏輯順序或依賴,返回順序取決于本身執(zhí)行完耗時 -> concurrentQueue()

  • 應(yīng)用場景3:不論任何函數(shù)生成的隊列,如果想指定 A隊列 與 B隊列 擁有相同優(yōu)先級 -> dispatch_set_target_queue()
    (知識點:優(yōu)先級 -> 并不是線程按等級順序來執(zhí)行完結(jié)束,而是系統(tǒng)處理器優(yōu)先分配處理,并不代表該線程最先處理完(只是會哭的孩子有奶吃!)

  • 應(yīng)用場景4:在追加多個處理全部結(jié)束后想執(zhí)行結(jié)束處理 -> dispatch_group()

  • 應(yīng)用場景5:訪問數(shù)據(jù)庫或文件時,為避免數(shù)據(jù)競爭 -> dispatch_barrier_async()

  • 應(yīng)用場景6:將Block指定次數(shù)的添加到Dispatch queue中 -> dispatch_apply()

  • 應(yīng)用場景7:在大量處理追加到queue中,對已添加過未執(zhí)行的處理進行管理(掛起/喚醒) -> dispatch_suspend__dispatch_resume()

  • 應(yīng)用場景8:在并行處理更新數(shù)據(jù),會產(chǎn)生數(shù)據(jù)不一的情況,雖然串行和柵欄函數(shù)(dispatch_barrier_async)也可以解決,但更細量化處理到任務(wù)中一個方法調(diào)用 -> dispatchSemaphore()

Demo

(可直接復(fù)制到Xcode中查看)

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self gcdApi];
    
}


-(void)gcdApi{

    [self dispatch_queue];
    
    [self dispatch_set_target_queue];
    
    [self dispatch_group];
    
    [self dispatch_barrier_async];
    
    [self dispatch_apply];

    [self dispatch_suspend__dispatch_resume];
    
    [self dispatchSemaphore];

}



/** 隊列
 
 - 1.串行(Serial dispatch、Main dispatch)
 - 2.并行(Concurrent dispatch)
 
 */

#pragma mark - Queue

-(void)dispatch_queue{


    [self serialQueue];
    
    [self concurrentQueue];
    
}

-(void)serialQueue{
    
    /**
     dispatch_queue_create 生成串行隊列
     
     - Parameters:
     - value1: 自定義
     - value2: NULL: 默認先進先出(FIFO) 即串行
     */
    dispatch_queue_t mySerial = dispatch_queue_create("com.example.gcd.MySerialQueue", NULL);
    
    /***
     * 異步線程加入串行隊列 -> 會開辟新線程 但執(zhí)行順序onebyone,有串行隊列性質(zhì)決定
     */
    dispatch_async(mySerial, ^{
        NSLog(@"serialQueue_task1");
    });
    dispatch_async(mySerial, ^{
        NSLog(@"serialQueue_task2");
    });
    
//    dispatch_release(mySerial);
}

-(void)concurrentQueue{
    
    /**
     全局隊列,并行
     
     @ Parameters:
         * value1: 優(yōu)先級 (注意:由于通過XNU內(nèi)核用于GCD并不能保證時效性,因此執(zhí)行高優(yōu)先級只是大致判斷并不精準,在處理的執(zhí)行可有可無下按優(yōu)先級)
             #define DISPATCH_QUEUE_PRIORITY_HIGH 2
             #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
             #define DISPATCH_QUEUE_PRIORITY_LOW (-2)
             #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
        * value2: 待留參數(shù),傳遞除0以外的任何值都可能導(dǎo)致一個空返回值
     */
    dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    /***
     * 異步線程加入全局隊列 -> 并行
     */
    dispatch_async(global, ^{
        NSLog(@"concurrentQueue_task1");
    });
    dispatch_async(global, ^{
        NSLog(@"concurrentQueue_task2");
    });
}


#pragma mark - dispatch_set_target_queue

-(void)dispatch_set_target_queue{
    
    dispatch_queue_t createSerial = dispatch_queue_create("com.exmple.gcd.targetSerialQueue", NULL);
    
    dispatch_queue_t globelBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    
    /***
     * createSerial 擁有 globelBackground 相同的優(yōu)先級
     */
    dispatch_set_target_queue(createSerial, globelBackground);
    
}


#pragma mark - dispatch_Group

-(void)dispatch_group{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk0");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk1");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk2");
    });
    
    /**
     * 追加三個Block到globel_queue中,等Block中全部執(zhí)行完畢,就會執(zhí)行 dispatch_get_main_queue中的Block
     */
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"Done!");
    });

    //也可以使用wait, DISPATCH_TIME_FOREVER表示一直等待,也可以是一段時間內(nèi)
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
//    NSLog(@"Done!");
    
    //blk0
    //blk1
    //blk2
    //Done!
    
}




#pragma mark - dispatch_barrier_async

-(void)dispatch_barrier_async{
    
    //用dispatch_queue_create函數(shù)生成一個Concurrent Dispatch Queue
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
    
    
    dispatch_async(concurrentQueue, ^{
        NSLog(@"blk0_reading");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"blk1_reading");
    });
    
    /**
     * 在blk1結(jié)束后,blk2開始前寫入,將Block追加到queue中,可以是異步/同步,同步須考慮避免死鎖
     */
    dispatch_barrier_async(concurrentQueue, ^{
        NSLog(@"blk_writing");
    });
    
    
    dispatch_async(concurrentQueue, ^{
        NSLog(@"blk2_reading");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"blk3_reading");
    });
    
}


#pragma mark - dispatch_apply

-(void)dispatch_apply{
    
    /**
     * 將Block指定次數(shù)的添加到Dispatch queue中,并開辟多個線程
     */
    dispatch_queue_t globel = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(10, globel, ^(size_t index) {
        NSLog(@"%zu",index);
    });
    NSLog(@"done");
    
    //2
    //3
    //6
    //...
    //9
    //done
    
}


#pragma mark - dispatch_suspend__dispatch_resume

-(void)dispatch_suspend__dispatch_resume{
    /**
     * 在大量處理追加到queue中,對已添加過未執(zhí)行的處理暫停 進行管理開關(guān)(掛起/喚醒)
     */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_suspend(queue);
    //dispatch_resume恢復(fù)指定的queue
    dispatch_resume(queue);
}


#pragma mark - dispatchSemaphore

-(void)dispatchSemaphore{
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);//創(chuàng)建信號量初始值為1
    
    NSMutableArray *arry = [[NSMutableArray alloc]init];
    
    for (int i = 0; i<1000; i++) {
        dispatch_async(queue, ^{
       
            //等待semaphore,計數(shù)為0時等待
            //一直等待,直到Dispatch_semaphore的計數(shù)值>=1減一并執(zhí)行
            
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//-1,
            /**
             * 由于semphore經(jīng)wait減一,此時計數(shù)值為0,可向下進行
             */
            //訪問arry類對象的線程,只有一個,可以安全訪問
            [arry addObject:@1];
            
            //onebyone
            dispatch_semaphore_signal(semaphore);//+1
            
    });
}
}

Github地址 : https://github.com/one-tea/GCD-API

參考資料:
grand-central-dispatch-in-depth-part:
https://github.com/nixzhu/dev-blog/blob/master/2014-04-19-grand-central-dispatch-in-depth-part-1.md
http://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2
iOS - 多線程你看全不全:https://juejin.im/entry/57dcc1cc0bd1d00057e97dc7
IOS多線程之GCD的執(zhí)行原理:http://www.itdecent.cn/p/5840523fb3ea

最后編輯于
?著作權(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)容

  • 前言 這是關(guān)于GCD的第二篇文章,GCD的API有100多個,通過快捷鍵Option + 單擊,可以在Refere...
    taogege666閱讀 369評論 0 0
  • GCD API函數(shù)整理 GCD(Grand Central Dispatch)是異步執(zhí)行任務(wù)的技術(shù)之一,一般將應(yīng)用...
    凌巔閱讀 427評論 0 0
  • 你好,我剛剛才下載的簡書,其實我也不懂怎么寫,我先自我介紹一下,我叫婷妹,今年13歲,。。。。。。。。。。
    香煙愛上火閱讀 121評論 0 1
  • 文/顧起辭歸 畢業(yè)典禮那天我坐在天臺上喝著啤酒吹著晚風,夏爾就坐在我身邊,他那天穿的是一件白色的短袖襯衫,風吹動我...
    顧起辭歸閱讀 621評論 1 2
  • 看完了,買很久了,在這個月的書單里面終于下定決心完成了。 開始看到這個書名的時候,只有兩個字“矯情”。是的啊,用這...
    安玲123閱讀 327評論 0 2

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