GCD(隊(duì)列組、信號(hào)量、柵欄函數(shù))實(shí)現(xiàn)多個(gè)請(qǐng)求都完成之后返回結(jié)果

隊(duì)列組

隊(duì)列組的簡(jiǎn)單使用 -- 監(jiān)聽(tīng)任務(wù)的完成

1、所有的任務(wù)會(huì)并發(fā)的執(zhí)行(不按序)

2、所有的異步函數(shù), 都是添加到隊(duì)列中, 然后再納入到隊(duì)列組的監(jiān)聽(tīng)范圍

3、使用dispatch_group_notify(隊(duì)列組, 隊(duì)列)函數(shù), 來(lái)監(jiān)聽(tīng)在這個(gè)函數(shù)上面的任務(wù)執(zhí)行是否完成, 當(dāng)任務(wù)完成, 就會(huì)調(diào)用這個(gè)方法

// 1. 創(chuàng)建隊(duì)列組
dispatch_group_t group = dispatch_group_create(); 
// 2. 創(chuàng)建并發(fā)隊(duì)列 
dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_CONCURRENT); 
// 3. 使用函數(shù)添加任務(wù) 
dispatch_group_async(group, queue, ^{ 
    NSLog(@"1---%@", [NSThread currentThread]);
 }); 
dispatch_group_async(group, queue, ^{
     NSLog(@"2---%@", [NSThread currentThread]); 
});
 dispatch_group_async(group, queue, ^{ 
    NSLog(@"3---%@", [NSThread currentThread]); 
}); 
dispatch_group_async(group, queue, ^{ 
    NSLog(@"4---%@", [NSThread currentThread]); 
}); 
// 4. 讓隊(duì)列組監(jiān)聽(tīng)任務(wù)的完成 
dispatch_group_notify(group, queue, ^{ 
    NSLog(@"執(zhí)行完畢"); 
});

信號(hào)量

問(wèn)題描述:

假設(shè)現(xiàn)在系統(tǒng)有兩個(gè)空閑資源可以被利用,但同一時(shí)間卻有三個(gè)線程要進(jìn)行訪問(wèn),這種情況下,該如何處理呢?

或者

我們要下載很多圖片,并發(fā)異步進(jìn)行,每個(gè)下載都會(huì)開(kāi)辟一個(gè)新線程,可是我們又擔(dān)心太多線程cpu肯定吃不消,那么我們這里也可以用信號(hào)量控制一下最大開(kāi)辟線程數(shù)。

定義:

1、信號(hào)量:就是一種可用來(lái)控制訪問(wèn)資源的線程數(shù)量的標(biāo)識(shí),設(shè)定了一個(gè)信號(hào)量,在線程訪問(wèn)之前,加上信號(hào)量的處理,則可告知系統(tǒng)按照我們指定的信號(hào)量數(shù)量來(lái)執(zhí)行多個(gè)線程。

其實(shí),這有點(diǎn)類似鎖機(jī)制了,只不過(guò)信號(hào)量都是系統(tǒng)幫助我們處理了,我們只需要在執(zhí)行線程之前,設(shè)定一個(gè)信號(hào)量值,并且在使用時(shí),加上信號(hào)量處理方法就行了。

2、信號(hào)量主要有3個(gè)函數(shù),分別是:

//創(chuàng)建信號(hào)量,參數(shù):信號(hào)量的初值,如果小于0則會(huì)返回NULL
dispatch_semaphore_create(信號(hào)量值)
//等待降低信號(hào)量
dispatch_semaphore_wait(信號(hào)量,等待時(shí)間)
//提高信號(hào)量
dispatch_semaphore_signal(信號(hào)量)

注意,正常的使用順序是先降低然后再提高,這兩個(gè)函數(shù)通常成對(duì)使用?!。ň唧w可參考下面的代碼示例)

3、那么就開(kāi)頭提的問(wèn)題,我們用代碼來(lái)解決

-(void)dispatchSignal{

    //crate的value表示,最多幾個(gè)資源可訪問(wèn)

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);    

    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    //任務(wù)1

    dispatch_async(quene, ^{

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        NSLog(@"run task 1");

        sleep(1);

        NSLog(@"complete task 1");

        dispatch_semaphore_signal(semaphore);        

    });

    //任務(wù)2

    dispatch_async(quene, ^{

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        NSLog(@"run task 2");

        sleep(1);

        NSLog(@"complete task 2");

        dispatch_semaphore_signal(semaphore);        

    });

    //任務(wù)3

    dispatch_async(quene, ^{

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        NSLog(@"run task 3");

        sleep(1);

        NSLog(@"complete task 3");

        dispatch_semaphore_signal(semaphore);        

    });    

}

執(zhí)行結(jié)果:


image.png

總結(jié):由于設(shè)定的信號(hào)值為2,先執(zhí)行兩個(gè)線程,等執(zhí)行完一個(gè),才會(huì)繼續(xù)執(zhí)行下一個(gè),保證同一時(shí)間執(zhí)行的線程數(shù)不超過(guò)2。

這里我們擴(kuò)展一下,假設(shè)我們?cè)O(shè)定信號(hào)值=1

dispatch_semaphore_create(1)

那么結(jié)果就是:

image.png

如果設(shè)定信號(hào)值=3

dispatch_semaphore_create(3)

那么結(jié)果就是:

image.png

其實(shí)設(shè)定為3,就是不限制線程執(zhí)行了,因?yàn)橐还膊胖挥?個(gè)線程。

柵欄函數(shù)

當(dāng)我們的任務(wù)有依賴關(guān)系的時(shí)候,比如任務(wù)1和2執(zhí)行完畢后才能執(zhí)行任務(wù)3和4,這時(shí)候我們可以用到這個(gè)函數(shù)——柵欄函數(shù)。其中 queue 是隊(duì)列,block 是任務(wù)。

提交一個(gè)柵欄函數(shù)在同步執(zhí)行中,它會(huì)等待柵欄函數(shù)執(zhí)行完再去執(zhí)行下一行代碼(注意是下一行代碼),同步柵欄函數(shù)是在當(dāng)前線程中執(zhí)行的

dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t blcok);

提交一個(gè)柵欄函數(shù)在異步執(zhí)行中,它會(huì)立馬返回開(kāi)始執(zhí)行下一行代碼(不用等待任務(wù)執(zhí)行完畢)

dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t blcok);
共同點(diǎn)

都會(huì)等待在它前面插入隊(duì)列的任務(wù)(1、2、3)先執(zhí)行完 2、都會(huì)等待他們自己的任務(wù)(barrier)執(zhí)行完再執(zhí)行后面的任務(wù)(4、5、6)(注意這里說(shuō)的是任務(wù)不是下一行代碼)

不同點(diǎn)

dispatch_barrier_sync需要等待自己的任務(wù)(barrier)結(jié)束之后,才會(huì)繼續(xù)添加并執(zhí)行寫(xiě)在barrier后面的任務(wù)(4、5、6),然后執(zhí)行后面的任務(wù) 2、dispatch_barrier_async將自己的任務(wù)(barrier)插入到queue之后,不會(huì)等待自己的任務(wù)結(jié)束,它會(huì)繼續(xù)把后面的任務(wù)(4、5、6)插入到queue,然后執(zhí)行任務(wù)。

// 并發(fā)隊(duì)列 柵欄函數(shù) 
- (void)concurrentQueueAsyncAndSync2BarrierTest {
    dispatch_queue_t queue = dispatch_queue_create("com.barrier", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)0 start");
        sleep(1);
        NSLog(@"任務(wù)0 end");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1 start");
        sleep(1);
        NSLog(@"任務(wù)1 end");
    });
    
    NSLog(@"同步柵欄 start ??");
    dispatch_barrier_sync(queue, ^{
        NSLog(@"同步柵欄 任務(wù) start");
        sleep(1);
        NSLog(@"同步柵欄 任務(wù) end");
    });
    NSLog(@"同步柵欄 end ??");
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2 start");
        sleep(1);
        NSLog(@"任務(wù)2 end");
    });
    
    NSLog(@"異步柵欄 start ??");
    dispatch_barrier_async(queue, ^{
        NSLog(@"異步柵欄柵欄 任務(wù) start");
        sleep(1);
        NSLog(@"異步柵欄柵欄 任務(wù) end");
    });
    NSLog(@"異步柵欄柵欄 end ??");
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3 start");
        sleep(1);
        NSLog(@"任務(wù)3 end");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)4 start");
        sleep(1);
        NSLog(@"任務(wù)4 end");
    });
}

打印結(jié)果如下:

2019-03-17 16:17:50.447824+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203368] 同步柵欄 start ??
2019-03-17 16:17:50.447838+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203589] 任務(wù)0 start
2019-03-17 16:17:50.447871+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203806] 任務(wù)1 start
2019-03-17 16:17:51.451935+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203806] 任務(wù)1 end
2019-03-17 16:17:51.451935+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203589] 任務(wù)0 end
2019-03-17 16:17:51.452211+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203368] 同步柵欄 任務(wù) start
2019-03-17 16:17:52.452917+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203368] 同步柵欄 任務(wù) end
2019-03-17 16:17:52.453108+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203368] 同步柵欄 end ??
2019-03-17 16:17:52.453240+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203368] 異步柵欄 start ??
2019-03-17 16:17:52.453280+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203809] 任務(wù)2 start
2019-03-17 16:17:52.453368+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203368] 異步柵欄柵欄 end ??
2019-03-17 16:17:53.067835+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203368] GCDBarrierController
2019-03-17 16:17:53.458678+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203809] 任務(wù)2 end
2019-03-17 16:17:53.458902+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203809] 異步柵欄柵欄 任務(wù) start
2019-03-17 16:17:54.462291+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203809] 異步柵欄柵欄 任務(wù) end
2019-03-17 16:17:54.462529+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203809] 任務(wù)3 start
2019-03-17 16:17:54.462534+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203806] 任務(wù)4 start
2019-03-17 16:17:55.465377+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203806] 任務(wù)4 end
2019-03-17 16:17:55.465391+0800 網(wǎng)絡(luò)請(qǐng)求Demo[3358:203809] 任務(wù)3 end
情景分析:

同步柵欄添加進(jìn)入隊(duì)列的時(shí)候,當(dāng)前線程會(huì)被鎖死,直到同步柵欄之前的任務(wù)和同步柵欄任務(wù)本身執(zhí)行完畢時(shí),當(dāng)前線程才會(huì)打開(kāi)然后繼續(xù)執(zhí)行下一句代碼。

注意:

在使用柵欄函數(shù)時(shí).使用自定義隊(duì)列才有意義,如果用的是串行隊(duì)列或者系統(tǒng)提供的全局并發(fā)隊(duì)列,這個(gè)柵欄函數(shù)的作用等同于一個(gè)同步函數(shù)的作用

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

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

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