GCD(一) —- 程序、線程、隊列、同步、異步 概念區分與使用
GCD(二) —- dispatch_semaphore 信号量
GCD(三) —- dispatch_group 排程群組
GCD(四) —- dispatch_apply 、dispatch_barrier
假設一下下面的場景:某APP首頁分為多個功能子產品,每個子產品使用不同的資料接口,為了提升使用者體驗,在加載首頁時可以先将所有子產品資料拿到後再加載UI,但不用考慮哪個子產品先得到資料。這種情況下使用GCD的
dispatch_group 排程群組
很容易處理。
dispatch_group 包含的函數
- dispatch_group_create()
生成 group 執行個體
- dispatch_group_async(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
group —— 一個排程群組
queue —— 任務執行隊列
block —— 任務内容
- dispatch_group_async_f(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#void * _Nullable context#>, <#dispatch_function_t _Nonnull work#>)
c語言函數
group —— 排程群組,與被送出的函數相關聯。該群組被系統保留,直到應用程式中定義好的函數執行完畢。不可以為NULL。
queue —— 排程隊列,用于送出系統定義好的函數,異步調用。該隊列被系統保留,直到應用程式定義好的函數執行完畢。不可以為NULL。
context —— 是由程式定義的,用于傳遞給work的參數。
work —— 應用程式定義的函數,在目标隊列中調用。work的第一個參數值是context。
- dispatch_group_enter(<#dispatch_group_t _Nonnull group#>)
調用一次該函數會使目前群組中未執行任務的計數加一,與
dispatch_group_leave
一起使用,兩者調用次數應保持一緻。
group —— 排程群組
- dispatch_group_leave(<#dispatch_group_t _Nonnull group#>)
調用一次該函數會使目前群組中未執行任務的計數減一,與
dispatch_group_enter
一起使用,兩者調用次數應保持一緻。
group —— 排程群組
- dispatch_group_wait(<#dispatch_group_t _Nonnull group#>, <#dispatch_time_t timeout#>)
等待排程群組關聯的block内任務執行完成,等待期間會堵塞目前線程,任務完成後恢複正常,執行後續任務。
group —— 排程群組
timeout —— 等待時間
- dispatch_group_notify(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
作用與
dispatch_group_wait
類似,但不會堵塞目前線程,并且可以指定group内任務完成之後後續任務的執行隊列,後續任務在block中執行
group —— 排程群組
queue —— 後續任務執行隊列
block —— 在這裡添加後續任務
使用dispatch_group_wait
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_group_t group = dispatch_group_create();
for (int index = ; index < ; index ++) {
dispatch_group_async(group, queue, ^{
NSLog(@"s1 線程:%@ -- index = %d",[NSThread currentThread],index);
[NSThread sleepForTimeInterval:f];
NSLog(@"s2 線程:%@ -- index = %d",[NSThread currentThread],index);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"執行後續任務");
使用dispatch_group_notify
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_group_t group = dispatch_group_create();
for (int index = ; index < ; index ++) {
dispatch_group_async(group, queue, ^{
NSLog(@"s1 線程:%@ -- index = %d",[NSThread currentThread],index);
[NSThread sleepForTimeInterval:f];
NSLog(@"s2 線程:%@ -- index = %d",[NSThread currentThread],index);
});
}
dispatch_group_notify(group, queue, ^{
NSLog(@"執行後續任務");
});
dispatch_group_enter 與 dispatch_group_leave 的使用
如果在排程群組關聯的block内直接異步送出新的任務,group 不會等待嵌套的異步任務執行完畢後在進入
dispatch_group_notify
和
dispatch_group_wait
狀态,如:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_group_t group = dispatch_group_create();
for (int index = ; index < ; index ++) {
dispatch_group_async(group, queue, ^{
NSLog(@"s1 線程:%@ -- index = %d",[NSThread currentThread],index);
[NSThread sleepForTimeInterval:f];
NSLog(@"s2 線程:%@ -- index = %d",[NSThread currentThread],index);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:f];
NSLog(@"s3 線程:%@ -- index = %d",[NSThread currentThread],index);
});
});
}
dispatch_group_notify(group, queue, ^{
NSLog(@"後續任務");
});
從結果可以看出,後續任務沒有在s1、s2、s3都執行完成後執行,此時就可以使用
dispatch_group_enter
告訴排程群有組新的任務加入,使未完成任務數增加;使用
dispatch_group_leave
使未完成任務數減少
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_group_t group = dispatch_group_create();
for (int index = ; index < ; index ++) {
dispatch_group_async(group, queue, ^{
NSLog(@"s1 線程:%@ -- index = %d",[NSThread currentThread],index);
[NSThread sleepForTimeInterval:f];
NSLog(@"s2 線程:%@ -- index = %d",[NSThread currentThread],index);
//有新任務加入
dispatch_group_enter(group);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:f];
NSLog(@"s3 線程:%@ -- index = %d",[NSThread currentThread],index);
//有任務完成
dispatch_group_leave(group);
});
});
}
dispatch_group_notify(group, queue, ^{
NSLog(@"後續任務");
});
此外,dispatch_group_enter 與 dispatch_group_leave 也可以直接使用,但需要保持兩者調用次數一緻,配合異步執行,其效果和 dispatch_group_async
類似
dispatch_group_async
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_group_t group = dispatch_group_create();
for (int index = ; index < ; index ++) {
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"s1 線程:%@ -- index = %d",[NSThread currentThread],index);
[NSThread sleepForTimeInterval:f];
NSLog(@"s2 線程:%@ -- index = %d",[NSThread currentThread],index);
dispatch_group_leave(group);
});
}
dispatch_group_notify(group, queue, ^{
NSLog(@"後續任務");
});