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)度組- group 指定的調(diào)度組儿捧,block的關(guān)聯(lián)調(diào)度組
- queue block指定的隊列
- 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)度組- group 指定的調(diào)度組,block的關(guān)聯(lián)調(diào)度組
- queue block指定的隊列
- context 傳遞到函數(shù)中的的參數(shù)
- 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í)行- group 給定調(diào)度組
- 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.- group 給定的調(diào)度組
- queue 給定的隊列.
- 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é)生定及時改正露泊。