GCD調(diào)度組的使用

GCD調(diào)度組(dispatch_group)的使用

GCD是Grand Central Dispatch的縮寫敏释,它主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對稱多處理系統(tǒng)肯污。它是一個在線程池模式的基礎(chǔ)上執(zhí)行的并發(fā)任務(wù)袭艺。日常開發(fā)中匠璧,GCD可以說是無處不在衙解,我們無時無刻都在用到它喉前。由于之前的工作內(nèi)容原因把将,對dispatch_group一直停留在理論階段轻专,沒有對其進行認真的實踐,如今換了新的公司秸弛,投入到新項目中的開發(fā)時铭若,才發(fā)現(xiàn)自己對于dispatch_group的認識是如此的淺薄,借此空檔時間递览,重新認識調(diào)度組并以此文章僅作為筆記叼屠,也算是對于近期使用調(diào)度組的總結(jié)。

調(diào)度組中常用的函數(shù)

  • dispatch_group_create(void);
    初始化一個調(diào)度組绞铃,創(chuàng)建成功返回dispatch_group調(diào)度組镜雨,失敗返回NULL
  • void dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
    提交一個任務(wù)(block)到指定的queue中,并關(guān)聯(lián)到指定的group調(diào)度組
    1. group 指定的調(diào)度組儿捧,block的關(guān)聯(lián)調(diào)度組
    2. queue block指定的隊列
    3. block 提交到指定隊列的block 通過typedef void (^dispatch_block_t)(void);該函數(shù)無法給block傳遞參數(shù)
  • void dispatch_group_async_f(dispatch_group_t group,dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
    提交一個函數(shù)指針(dispatch_function_t)到queue中荚坞,并關(guān)聯(lián)到指定的group調(diào)度組
    1. group 指定的調(diào)度組,block的關(guān)聯(lián)調(diào)度組
    2. queue block指定的隊列
    3. context 傳遞到函數(shù)中的的參數(shù)
    4. work 在指定的queue中的指定函數(shù)菲盾。
  • void dispatch_group_enter(dispatch_group_t group);
  • void dispatch_group_leave(dispatch_group_t group);
    將一個block提交到指定的queue上并關(guān)聯(lián)到group調(diào)度組.兩個函數(shù)必須成對出現(xiàn)颓影,如果leave比enter多,則將造成內(nèi)存泄露
  • dispatch_group_wait(<#dispatch_group_t_Nonnullgroup#>,<#dispatch_time_t timeout#>)
    執(zhí)行等待懒鉴,等待所有關(guān)聯(lián)到group調(diào)度組的block執(zhí)行完成诡挂,或者等待timeout發(fā)生超時,當(dāng)在超時時間timeout內(nèi)執(zhí)行完了所有的block函數(shù),則返回0,否則返回非0值临谱,只有執(zhí)行完了此函數(shù)璃俗,此函數(shù)后面的方法才會執(zhí)行
    1. group 給定調(diào)度組
    2. timeout 如果group調(diào)度組里邊的block執(zhí)行時間非常長,函數(shù)的等待時間.
  • void
    dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
    該函數(shù)指定了一個block,當(dāng)group調(diào)度組里邊的所有block都執(zhí)行完成時悉默,將通知block關(guān)聯(lián)到group中城豁,并加入到給定的queue隊列里,當(dāng)group調(diào)度組當(dāng)前沒有任何block關(guān)聯(lián)的時候?qū)⒘⒓磳lock提交到queue隊列,并與group調(diào)度組關(guān)聯(lián),該函數(shù)返回void.
    1. group 給定的調(diào)度組
    2. queue 給定的隊列.
    3. block 給定的閉包函數(shù).
  • void dispatch_group_notify_f(dispatch_group_t group,dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
    與disptch_group_notify類似,提交的一個函數(shù)work作為執(zhí)行體抄课,context是執(zhí)行時傳遞的參數(shù)唱星,該函數(shù)返回void.

理論需要實踐

  • 通過dispatch_group_asyn的方法將任務(wù)添加到隊列中并將任務(wù)關(guān)聯(lián)到調(diào)度組中
//通過dispatch_group_asyn的方法將任務(wù)添加到隊列中
- (void)asyncAddTaskToQueueAndGroupByDispatch_group {
    //創(chuàng)建調(diào)度組
    dispatch_group_t group = dispatch_group_create();
    //創(chuàng)建指定的隊列
    //串行隊列
    dispatch_queue_t serialQueue = dispatch_queue_create("net.jihuigou.serialQueue", DISPATCH_QUEUE_SERIAL);
    //串行隊列之主隊列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    //并發(fā)隊列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("net.jihuigou.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue = concurrentQueue;
    //將任務(wù)添加到隊列中并關(guān)聯(lián)調(diào)度組
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"任務(wù)1---------被執(zhí)行-%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"任務(wù)2--------被執(zhí)行-%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"任務(wù)3-------被執(zhí)行-%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務(wù)4-------被執(zhí)行-%@",[NSThread currentThread]);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"當(dāng)前任務(wù)均處理完成---%@",[NSThread currentThread]);
    });
    
    NSLog(@"代碼執(zhí)行到這了");
}
輸出結(jié)果:
    2019-10-29 11:43:08.619037+0800 RACDemo[31421:474129] 代碼執(zhí)行到這了
     2019-10-29 11:43:08.619120+0800 RACDemo[31421:474181] 任務(wù)4-------被執(zhí)行-<NSThread: 0x600003fc5c80>{number = 3, name = (null)}
     2019-10-29 11:43:10.622480+0800 RACDemo[31421:474182] 任務(wù)1---------被執(zhí)行-<NSThread: 0x600003fc85c0>{number = 4, name = (null)}
     2019-10-29 11:43:10.622480+0800 RACDemo[31421:474188] 任務(wù)2--------被執(zhí)行-<NSThread: 0x600003fccd80>{number = 5, name = (null)}
     2019-10-29 11:43:10.622503+0800 RACDemo[31421:474187] 任務(wù)3-------被執(zhí)行-<NSThread: 0x600003ff4540>{number = 6, name = (null)}
     2019-10-29 11:43:10.622726+0800 RACDemo[31421:474129] 當(dāng)前任務(wù)均處理完成---<NSThread: 0x600003fa2480>{number = 1, name = main}

此處使用并發(fā)隊列作為任務(wù)添加的指定隊列,從輸出結(jié)果中可以看出跟磨,任務(wù)執(zhí)行順序不定魏颓,并且開啟了多條線程,并且首先先打印了dispatch_group_notify后面的結(jié)果吱晒。只有調(diào)度組中關(guān)聯(lián)的所有任務(wù)都完成甸饱,才會執(zhí)行dispatch_group_notify方法中的block,

  • dispatch_group_enter&dispatch_group_leave
    - (void)dispatchGroupEnterAndLeaveDemo {
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t serialQueue = dispatch_queue_create("net.jihuigou.serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_queue_t concurrentQueue = dispatch_queue_create("net.jihuigou.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_queue_t queue = concurrentQueue;
    
    dispatch_group_enter(group);
    //將任務(wù)添加到隊列中并關(guān)聯(lián)調(diào)度組
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"任務(wù)1---------被執(zhí)行-%@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"任務(wù)2--------被執(zhí)行-%@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"任務(wù)3-------被執(zhí)行-%@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務(wù)4-------被執(zhí)行-%@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"當(dāng)前任務(wù)均處理完成---%@",[NSThread currentThread]);
    });
    
    NSLog(@"代碼執(zhí)行到這了");
}
輸出結(jié)果:
2019-10-29 13:45:47.183447+0800 RACDemo[32346:503834] 代碼執(zhí)行到這了
2019-10-29 13:45:47.183523+0800 RACDemo[32346:503918] 任務(wù)4-------被執(zhí)行-<NSThread: 0x6000037b3100>{number = 3, name = (null)}
2019-10-29 13:45:49.186933+0800 RACDemo[32346:503913] 任務(wù)3-------被執(zhí)行-<NSThread: 0x6000037a9ec0>{number = 4, name = (null)}
2019-10-29 13:45:49.186999+0800 RACDemo[32346:503914] 任務(wù)1---------被執(zhí)行-<NSThread: 0x6000037a9ac0>{number = 5, name = (null)}
2019-10-29 13:45:49.187004+0800 RACDemo[32346:503912] 任務(wù)2--------被執(zhí)行-<NSThread: 0x600003783600>{number = 6, name = (null)}
2019-10-29 13:45:49.187255+0800 RACDemo[32346:503834] 當(dāng)前任務(wù)均處理完成---<NSThread: 0x6000037e28c0>{number = 1, name = main}

這里的輸出結(jié)果與上一個結(jié)果類似,dispatch_group_notify中block的內(nèi)容等調(diào)度組中所有的任務(wù)都結(jié)束才執(zhí)行叹话,與dispatch_group_async不同的是偷遗,這里dispatch_group_enter是進組,相當(dāng)于給調(diào)度組添加任務(wù)驼壶,調(diào)度組內(nèi)的任務(wù)數(shù)+1氏豌,dispatch_group_leave是出組,調(diào)度組內(nèi)的任務(wù)數(shù)-1热凹,相當(dāng)于該任務(wù)已經(jīng)完成泵喘,只有enter和leave此處相同,即調(diào)度組內(nèi)的任務(wù)數(shù)為0,才會收到調(diào)度組任務(wù)完成的通知般妙,執(zhí)行dispatch_group_notify

注意的點

  • 如果使用dispatch_group_async的方式將任務(wù)添加到隊列并關(guān)聯(lián)到調(diào)度組中纪铺,添加的任務(wù)里應(yīng)又存在異步的操作,這樣打印結(jié)果是否和上面的一樣呢碟渺?
- (void)dispatchGroupAsyncDemo {
    //創(chuàng)建調(diào)度組
    dispatch_group_t group = dispatch_group_create();
    //創(chuàng)建指定的隊列
    //串行隊列
    dispatch_queue_t serialQueue = dispatch_queue_create("net.jihuigou.serialQueue", DISPATCH_QUEUE_SERIAL);
    //串行隊列之主隊列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    //并發(fā)隊列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("net.jihuigou.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue = concurrentQueue;
    //將任務(wù)添加到隊列中并關(guān)聯(lián)調(diào)度組
    dispatch_group_async(group, queue, ^{
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:2];//模擬異步操作
            NSLog(@"任務(wù)1---------被執(zhí)行-%@",[NSThread currentThread]);
        });
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務(wù)2--------被執(zhí)行-%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務(wù)3-------被執(zhí)行-%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務(wù)4-------被執(zhí)行-%@",[NSThread currentThread]);
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"當(dāng)前任務(wù)均處理完成---%@",[NSThread currentThread]);
    });
    NSLog(@"代碼執(zhí)行到這了");    
}
輸出結(jié)果
2019-10-29 14:25:21.025384+0800 RACDemo[33234:521186] 任務(wù)2--------被執(zhí)行-<NSThread: 0x6000031d0dc0>{number = 3, name = (null)}
2019-10-29 14:25:21.025531+0800 RACDemo[33234:521187] 任務(wù)3-------被執(zhí)行-<NSThread: 0x6000031d0f80>{number = 4, name = (null)}
2019-10-29 14:25:21.025699+0800 RACDemo[33234:521187] 任務(wù)4-------被執(zhí)行-<NSThread: 0x6000031d0f80>{number = 4, name = (null)}
2019-10-29 14:25:21.025676+0800 RACDemo[33234:521134] 代碼執(zhí)行到這了
2019-10-29 14:25:21.058502+0800 RACDemo[33234:521134] 當(dāng)前任務(wù)均處理完成---<NSThread: 0x6000031be5c0>{number = 1, name = main}
2019-10-29 14:25:23.029060+0800 RACDemo[33234:521190] 任務(wù)1---------被執(zhí)行-<NSThread: 0x6000031d9300>{number = 5, name = (null)}

從輸出結(jié)果鲜锚,我們可以看出,任務(wù)1的打印在dispatch_group_notify的打印之后苫拍,這樣的結(jié)果明顯不是我們使用調(diào)度組所希望的芜繁,所以,在使用dispatch_group_async添加任務(wù)時绒极,被添加的任務(wù)不應(yīng)該存在異步的操作骏令,對于任務(wù)中存在異步的操作,解決方案是使用手動的進組出組方式垄提,即dispatch_group_enter() dispatch_group_leave()榔袋,這樣就達到我們所想的效果了

這里是修改后的任務(wù)1
 dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:2];//模擬異步操作
            NSLog(@"任務(wù)1---------被執(zhí)行-%@",[NSThread currentThread]);
            dispatch_group_leave(group);
        });
    });
輸出結(jié)果:
2019-10-29 14:30:35.063698+0800 RACDemo[33393:523444] 代碼執(zhí)行到這了
2019-10-29 14:30:35.063768+0800 RACDemo[33393:523505] 任務(wù)2--------被執(zhí)行-<NSThread: 0x600000111c80>{number = 3, name = (null)}
2019-10-29 14:30:35.063770+0800 RACDemo[33393:523503] 任務(wù)3-------被執(zhí)行-<NSThread: 0x600000125e00>{number = 4, name = (null)}
2019-10-29 14:30:35.063770+0800 RACDemo[33393:523506] 任務(wù)4-------被執(zhí)行-<NSThread: 0x600000117c40>{number = 5, name = (null)}
2019-10-29 14:30:37.068327+0800 RACDemo[33393:523507] 任務(wù)1---------被執(zhí)行-<NSThread: 0x60000012b680>{number = 6, name = (null)}
2019-10-29 14:30:37.068589+0800 RACDemo[33393:523444] 當(dāng)前任務(wù)均處理完成---<NSThread: 0x6000001610c0>{number = 1, name = main}
  • dispatch_group_notify和dispatch_group_wait的區(qū)別
    dispatch_group_notify和dispatch_group_wait都是等待調(diào)度組中所有的任務(wù)都完成之后才執(zhí)行各自block中的內(nèi)容,不同的是塔淤,dispatch_group_notify是通過通知來實現(xiàn)的,不會阻塞主線程速妖,而dispatch_group_wait是同步的高蜂,只有等到調(diào)度組中所有的任務(wù)都完成了,并且dispatch_group_wiat也執(zhí)行了罕容,才會接著執(zhí)行dispatch_group_wait之后的代碼

以上即我近期使用dispatch_group的一些經(jīng)驗和心得备恤,學(xué)生資歷淺薄,若有說的不對的地方還望各位大佬指出锦秒,學(xué)生定及時改正露泊。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市旅择,隨后出現(xiàn)的幾起案子惭笑,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沉噩,死亡現(xiàn)場離奇詭異捺宗,居然都是意外死亡,警方通過查閱死者的電腦和手機川蒙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門蚜厉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人畜眨,你說我怎么就攤上這事昼牛。” “怎么了康聂?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵贰健,是天一觀的道長。 經(jīng)常有香客問我早抠,道長霎烙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任蕊连,我火速辦了婚禮悬垃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甘苍。我一直安慰自己尝蠕,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布载庭。 她就那樣靜靜地躺著看彼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪囚聚。 梳的紋絲不亂的頭發(fā)上靖榕,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音顽铸,去河邊找鬼茁计。 笑死,一個胖子當(dāng)著我的面吹牛谓松,可吹牛的內(nèi)容都是我干的星压。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼鬼譬,長吁一口氣:“原來是場噩夢啊……” “哼娜膘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起优质,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤竣贪,失蹤者是張志新(化名)和其女友劉穎军洼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贾富,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡歉眷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了颤枪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汗捡。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖畏纲,靈堂內(nèi)的尸體忽然破棺而出扇住,到底是詐尸還是另有隱情,我是刑警寧澤盗胀,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布艘蹋,位于F島的核電站,受9級特大地震影響票灰,放射性物質(zhì)發(fā)生泄漏女阀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一屑迂、第九天 我趴在偏房一處隱蔽的房頂上張望浸策。 院中可真熱鬧,春花似錦惹盼、人聲如沸庸汗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚯舱。三九已至,卻和暖如春掩蛤,著一層夾襖步出監(jiān)牢的瞬間枉昏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工揍鸟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留兄裂,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓蜈亩,卻偏偏與公主長得像懦窘,于是被迫代替她去往敵國和親前翎。 傳聞我的和親對象是個殘疾皇子稚配,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容