GCD

目錄

  • 知識(shí)點(diǎn)概況
  • 隊(duì)列和任務(wù)
  • 并發(fā)和并行
  • 常用場(chǎng)景

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

GCD中有2個(gè)核心概念:

1. 任務(wù)和隊(duì)列

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

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

    • 串行隊(duì)列(Serial Dispatch Queue)
      讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù))
    • 并行隊(duì)列(Concurrent Dispatch Queue)
      可以讓多個(gè)任務(wù)并行(同時(shí))執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程同時(shí)執(zhí)行任務(wù))

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

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

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


image.png

3. GCD API 常用場(chǎng)景

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

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

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

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

  • 應(yīng)用場(chǎng)景5:訪問(wèn)數(shù)據(jù)庫(kù)或文件時(shí),為避免數(shù)據(jù)競(jìng)爭(zhēng) -> dispatch_barrier_async()

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

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

  • 應(yīng)用場(chǎng)景8:在并行處理更新數(shù)據(jù),會(huì)產(chǎn)生數(shù)據(jù)不一的情況,雖然串行和柵欄函數(shù)(dispatch_barrier_async)也可以解決,但更細(xì)量化處理到任務(wù)中一個(gè)方法調(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];

}



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

#pragma mark - Queue

-(void)dispatch_queue{


    [self serialQueue];
    
    [self concurrentQueue];
    
}

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

-(void)concurrentQueue{
    
    /**
     全局隊(duì)列,并行
     
     @ Parameters:
         * value1: 優(yōu)先級(jí) (注意:由于通過(guò)XNU內(nèi)核用于GCD并不能保證時(shí)效性,因此執(zhí)行高優(yōu)先級(jí)只是大致判斷并不精準(zhǔn),在處理的執(zhí)行可有可無(wú)下按優(yōu)先級(jí))
             #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)致一個(gè)空返回值
     */
    dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    /***
     * 異步線程加入全局隊(duì)列 -> 并行
     */
    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)先級(jí)
     */
    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");
    });
    
    /**
     * 追加三個(gè)Block到globel_queue中,等Block中全部執(zhí)行完畢,就會(huì)執(zhí)行 dispatch_get_main_queue中的Block
     */
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"Done!");
    });

    //也可以使用wait, DISPATCH_TIME_FOREVER表示一直等待,也可以是一段時(shí)間內(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ù)生成一個(gè)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開(kāi)始前寫入,將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中,并開(kāi)辟多個(gè)線程
     */
    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中,對(duì)已添加過(guò)未執(zhí)行的處理暫停 進(jìn)行管理開(kāi)關(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)建信號(hào)量初始值為1
    
    NSMutableArray *arry = [[NSMutableArray alloc]init];
    
    for (int i = 0; i<1000; i++) {
        dispatch_async(queue, ^{
       
            //等待semaphore,計(jì)數(shù)為0時(shí)等待
            //一直等待,直到Dispatch_semaphore的計(jì)數(shù)值>=1減一并執(zhí)行
            
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//-1,
            /**
             * 由于semphore經(jīng)wait減一,此時(shí)計(jì)數(shù)值為0,可向下進(jìn)行
             */
            //訪問(wèn)arry類對(duì)象的線程,只有一個(gè),可以安全訪問(wèn)
            [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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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

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