GCD 實(shí)現(xiàn)多個(gè)異步的同步執(zhí)行-dispatch_group_t和dispatch_semaphore_t

一. dispatch_group_t 用法

1. dispatch_group_t 執(zhí)行同步操作
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t globeQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_async(group, globeQ, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"1--over");

    });
    dispatch_group_async(group, globeQ, ^{
        [NSThread sleepForTimeInterval:5];
        NSLog(@"2--over");
        
    });
    
    dispatch_group_async(group, globeQ, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"3--over");
        
    });
    
    
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"全部結(jié)束......");
    });
    
    NSLog(@" waiting... ");

運(yùn)行,打印結(jié)果如下

2017-07-26 15:10:07.166248 測(cè)試用test[15173:289444]  waiting... 
2017-07-26 15:10:09.170468 測(cè)試用test[15173:289523] 3--over
2017-07-26 15:10:10.167656 測(cè)試用test[15173:289495] 1--over
2017-07-26 15:10:12.170615 測(cè)試用test[15173:289497] 2--over
2017-07-26 15:10:12.170749 測(cè)試用test[15173:289497] 全部結(jié)束......

從上面的步驟可以得出
I.異步操作,異步 并且 無序執(zhí)行;
II.三個(gè)dispatch_group 執(zhí)行全部完成之后,會(huì)執(zhí)行 dispatch_group_notify里面的block
III.waiting...立即執(zhí)行,dispatch_group_t不會(huì)阻塞當(dāng)前線程;

但是,當(dāng)dispatch_group_asyncblock里面執(zhí)行的是異步任務(wù),如果還是使用上面的方法你會(huì)發(fā)現(xiàn)異步任務(wù)還沒跑完就已經(jīng)進(jìn)入到了dispatch_group_notify里面的block.例如下面:
    dispatch_group_t group = dispatch_group_create();
//    dispatch_queue_t globeQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t concurrentQ = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, concurrentQ, ^{
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"1--over");
        });
    });
    dispatch_group_async(group, concurrentQ, ^{
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"2--over");
        });

    });
    
    dispatch_group_async(group, concurrentQ, ^{
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3--over");
        });
    });
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"全部結(jié)束......");
    });
    
    NSLog(@" waiting... ");

運(yùn)行,打印結(jié)果如下

2017-07-26 15:23:14.959950 測(cè)試用test[15550:300115]  waiting... 
2017-07-26 15:23:14.960001 測(cè)試用test[15550:300152] 全部結(jié)束......
2017-07-26 15:23:16.962408 測(cè)試用test[15550:300168] 3--over
2017-07-26 15:23:17.960724 測(cè)試用test[15550:300154] 1--over
2017-07-26 15:23:19.962464 測(cè)試用test[15550:300164] 2--over

從上面的結(jié)果可看出, 當(dāng)執(zhí)行是異步操作的 使用上面的方法無法滿足要求.這時(shí)用到dispatch_group_enterdispatch_group_leave就可以解決這個(gè)問題:

2. dispatch_group_t 執(zhí)行的是異步操作

示例

   
    dispatch_group_t group = dispatch_group_create();
//    dispatch_queue_t globeQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t concurrentQ = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_enter(group);
  
    dispatch_async(concurrentQ, ^{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"1--over");
            dispatch_group_leave(group);
        });

    });
  dispatch_group_enter(group);
   
    dispatch_async(concurrentQ, ^{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"2--over");
            dispatch_group_leave(group);
        });
       
    });
    dispatch_group_enter(group);//可以寫在每個(gè)組前面,也可以全部提到任務(wù)最前面

    dispatch_async(concurrentQ, ^{
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3--over");
            dispatch_group_leave(group);
        });
        
    });

    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"全部結(jié)束......");
    });

    NSLog(@" waiting... ");

創(chuàng)建好任務(wù)組后,執(zhí)行加入任務(wù)組的操作代碼。dispatch_enterdispatch_leave要成對(duì)出現(xiàn),否則奔潰。
運(yùn)行,打印如下:

2017-07-26 15:35:09.359028 測(cè)試用test[15895:310263]  waiting... 
2017-07-26 15:35:11.362995 測(cè)試用test[15895:310296] 3--over
2017-07-26 15:35:12.361839 測(cè)試用test[15895:310297] 1--over
2017-07-26 15:35:14.364044 測(cè)試用test[15895:310321] 2--over
2017-07-26 15:35:14.364166 測(cè)試用test[15895:310321] 全部結(jié)束......

滿足需求,OK!!

二. dispatch_semaphore_t 用法

示例:

執(zhí)行的是同步操作

 for (int i = 0; i<3; ++i) {
        
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        dispatch_queue_t globeQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    
        dispatch_async(globeQ, ^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"%d--over",i+1);
            dispatch_semaphore_signal(semaphore); 
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"%d--through",i+1);
    }
    NSLog(@" waiting... ");

執(zhí)行的是異步操作

    for (int i = 0; i<3; ++i) {
        
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        
//        dispatch_queue_t globeQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_queue_t concurrentQ = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(concurrentQ, ^{
        
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                [NSThread sleepForTimeInterval:3];
                NSLog(@"%d--over",i+1);
                dispatch_semaphore_signal(semaphore);
            });
          
            
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        NSLog(@"%d--through",i+1);
        
    }
    NSLog(@" waiting... ");

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 如果semaphore計(jì)數(shù)大于等于1.計(jì)數(shù)-1,返回,程序繼續(xù)運(yùn)行。如果計(jì)數(shù)為0,則等待。這里設(shè)置的等待時(shí)間是一直等待。dispatch_semaphore_signal(semaphore);計(jì)數(shù)+1.在這兩句代碼中間的執(zhí)行代碼,每次只會(huì)允許一個(gè)線程進(jìn)入,這樣就有效的保證了在多線程環(huán)境下,只能有一個(gè)線程進(jìn)入。

運(yùn)行,打印結(jié)果全部如下

2017-07-26 13:57:20.748453 測(cè)試用test[9697:223538] 1--over
2017-07-26 13:57:20.748523 測(cè)試用test[9697:223493] 1--through
2017-07-26 13:57:23.750806 測(cè)試用test[9697:223538] 2--over
2017-07-26 13:57:23.750881 測(cè)試用test[9697:223493] 2--through
2017-07-26 13:57:26.754020 測(cè)試用test[9697:223538] 3--over
2017-07-26 13:57:26.754095 測(cè)試用test[9697:223493] 3--through
2017-07-26 13:57:26.754117 測(cè)試用test[9697:223493]  waiting... 

從上面的步驟可以得出
I.異步操作,同步 并且 順序執(zhí)行;
II.waiting... 最后執(zhí)行,dispatch_semaphore_t 信號(hào)量會(huì)阻塞當(dāng)前進(jìn)程;

綜合對(duì)比,兩種方式都可以滿足 實(shí)現(xiàn)異步同步執(zhí)行的需求,具體選擇 就要看個(gè)人了...

!!! 一定要注意不要再主線程中使用信號(hào)量dispatch_semaphore_t,除非你有阻塞主線程的需求.一定要將操作放在異步線程.

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時(shí)候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,402評(píng)論 21 42
  • Managing Units of Work(管理工作單位) 調(diào)度塊允許您直接配置隊(duì)列中各個(gè)工作單元的屬性。它們還...
    edison0428閱讀 8,225評(píng)論 0 1
  • 一、多線程簡(jiǎn)介: 所謂多線程是指一個(gè) 進(jìn)程 -- process(可以理解為系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序)中可以開...
    尋形覓影閱讀 1,183評(píng)論 0 6
  • 談到iOS多線程,一般都會(huì)談到四種方式:pthread、NSThread、GCD和NSOperation。其中,蘋...
    攻城獅GG閱讀 362評(píng)論 0 3
  • 如果有一天失業(yè)了,行業(yè)不景氣了 http://www.zhihu.com/question/36194332/an...
    CinWind閱讀 172評(píng)論 0 0

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