天天看點

GCD(三) ---- dispatch_group 排程群組

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(@"執行後續任務");
           
GCD(三) ---- dispatch_group 排程群組

使用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(@"執行後續任務");
});
           
GCD(三) ---- dispatch_group 排程群組

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(@"後續任務");
});
           
GCD(三) ---- dispatch_group 排程群組

從結果可以看出,後續任務沒有在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(@"後續任務");
});
           
GCD(三) ---- dispatch_group 排程群組

此外,dispatch_group_enter 與 dispatch_group_leave 也可以直接使用,但需要保持兩者調用次數一緻,配合異步執行,其效果和

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(@"後續任務");
});
           

繼續閱讀