GCD Group、Barrier、Semaphore、NSOperationQueue使用

先貼上打印函數(shù):

- (void)p_printThread:(int)index {
    NSLog(@"%@-------%d", [NSThread currentThread], index);
}

1. Group

Group作用:在并發(fā)異步隊(duì)列中,等待執(zhí)行一系列任務(wù)后,再執(zhí)行一個(gè)任務(wù)。實(shí)現(xiàn)方式有兩種:notify和wait。
notify示例代碼:

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, concurrentQueue, ^{ 
        [self p_printThread:1];
    });
    dispatch_group_async(group, concurrentQueue, ^{ 
        [self p_printThread:2];
    });
    dispatch_group_async(group, concurrentQueue, ^{
        [self p_printThread:3];
    });
    dispatch_group_async(group, concurrentQueue, ^{ 
        [self p_printThread:4];
    });
    // 使用dispatch_group_wait,可以阻塞線程,等待group的任務(wù)執(zhí)行完畢,才能繼續(xù)執(zhí)行后續(xù)任務(wù)
    // 使用dispatch_group_notify,不會(huì)阻塞線程(group外的線程執(zhí)行順序不受影響),而且可以在執(zhí)行完成group的任務(wù)后進(jìn)行操作
    dispatch_group_notify(group, concurrentQueue, ^{
        [self p_printThread:0];
    });

打印結(jié)果:

<NSThread: 0x610000260d80>{number = 4, name = (null)}-------2
<NSThread: 0x608000261400>{number = 5, name = (null)}-------3
<NSThread: 0x618000264f40>{number = 3, name = (null)}-------1
<NSThread: 0x610000260e40>{number = 6, name = (null)}-------4
<NSThread: 0x610000260e40>{number = 6, name = (null)}-------0

wait示例代碼:

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    for (int i=0; i<4; i++)  {
        dispatch_group_enter(group);
        dispatch_async(concurrentQueue, ^{
            [self p_printThread:i+1];
        });   
        dispatch_group_leave(group);
    }
    // 使用dispatch_group_wait,可以阻塞線程,等待group的任務(wù)執(zhí)行完畢
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_async(dispatch_get_main_queue(), ^{
        // 主線程處理
        [self p_printThread:0];
    });

打印結(jié)果:

<NSThread: 0x600000076600>{number = 4, name = (null)}-------2
<NSThread: 0x600000076740>{number = 6, name = (null)}-------4
<NSThread: 0x610000073280>{number = 3, name = (null)}-------1
<NSThread: 0x608000076380>{number = 5, name = (null)}-------3
<NSThread: 0x60000007b240>{number = 1, name = main}-------0

結(jié)論:運(yùn)行多次,任務(wù)1、2、3、4的順序不定,但任務(wù)0總是最后一個(gè)。應(yīng)用場(chǎng)景:?jiǎn)谓缑娑嗾?qǐng)求完成后,主線程刷新界面;notify和wait的區(qū)別:wait會(huì)阻塞線程,notify不會(huì)阻塞線程,較好一點(diǎn)

2. Barrier

Barrier作用:Barrier在并發(fā)異步隊(duì)列中起到承上啟下的作用(Barrier就像名字一樣,類似一個(gè)柵欄把前后的任務(wù)隔開了)。Barrier前后任務(wù)執(zhí)行順序?yàn)椋築arrier前面的線程(多個(gè)的話,仍是并行)--->barrier線程--->barrier后面的線程(多個(gè)的話,仍是并行)。需要注意的是:Barrier在全局并發(fā)隊(duì)列不起作用,只有在自己創(chuàng)建的并發(fā)隊(duì)列才起作用。

示例代碼:

// barrier在dispatch_get_global_queue創(chuàng)建的并行隊(duì)列中不起作用,需要使用dispatch_queue_create來(lái)創(chuàng)建的并行隊(duì)列才可以
    //dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:1];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:2];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:3];
    });
    dispatch_barrier_async(concurrentQueue, ^(){
        [self p_printThread:0];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:4];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:5];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:6];
    });

打印結(jié)果:

<NSThread: 0x600000079300>{number = 4, name = (null)}-------2
<NSThread: 0x6000000790c0>{number = 5, name = (null)}-------3
<NSThread: 0x610000076100>{number = 3, name = (null)}-------1
<NSThread: 0x610000076100>{number = 3, name = (null)}-------0
<NSThread: 0x610000076100>{number = 3, name = (null)}-------4
<NSThread: 0x600000079300>{number = 4, name = (null)}-------6
<NSThread: 0x600000078d40>{number = 6, name = (null)}-------5

結(jié)論:運(yùn)行多次后可以看出,Barrier的任務(wù)0總是在任務(wù)1、2、3之后,而且總是在任務(wù)4、5、6之前,但是任務(wù)1、2、3的執(zhí)行順序不定,任務(wù)4、5、6的執(zhí)行順序也不定。Barrier的任務(wù)就像“柵欄”一樣隔開了前后的任務(wù)。

3. Semaphore

Semaphore作用:信號(hào)量可以用來(lái)控制同時(shí)訪問(wèn)資源的線程數(shù)量:比如系統(tǒng)只有兩個(gè)資源可以用,有三個(gè)線程要訪問(wèn),那么只能允許兩個(gè)線程同時(shí)訪問(wèn),第三個(gè)線程應(yīng)當(dāng)?shù)却Y源被釋放后再訪問(wèn)。使用信號(hào)量可以實(shí)現(xiàn)類似于NSOperationQueue里的并發(fā)控制:信號(hào)數(shù)>0,執(zhí)行任務(wù);信號(hào)數(shù)<=0,阻塞線程
示例代碼:

// 下面的例子只允許3個(gè)線程同時(shí)執(zhí)行
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);// 創(chuàng)建一個(gè)信號(hào)量,初始值為3
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i=0; i<10; i++) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);// 計(jì)數(shù)-1
        dispatch_async(concurrentQueue, ^{
            [self p_printThread:i];
            sleep(5);
            dispatch_semaphore_signal(semaphore);// 計(jì)數(shù)+1
        });
    }

打印結(jié)果:
<NSThread: 0x608000077b80>{number = 5, name = (null)}-------2
<NSThread: 0x610000074fc0>{number = 3, name = (null)}-------0
<NSThread: 0x6000000787c0>{number = 4, name = (null)}-------1

<NSThread: 0x6000000787c0>{number = 4, name = (null)}-------3
<NSThread: 0x610000074fc0>{number = 3, name = (null)}-------4
<NSThread: 0x608000077b80>{number = 5, name = (null)}-------5

<NSThread: 0x6000000787c0>{number = 4, name = (null)}-------7
<NSThread: 0x608000077b80>{number = 5, name = (null)}-------6
<NSThread: 0x610000074fc0>{number = 3, name = (null)}-------8

<NSThread: 0x610000074fc0>{number = 3, name = (null)}-------9
結(jié)論:由于信號(hào)量的值為3,每次只能同時(shí)執(zhí)行3個(gè)線程里的任務(wù)

4. NSOperationQueue

NSOperationQueue作用:
1.將NSOperation添加到NSOperationQueue,使其異步執(zhí)行 === GCD并行異步隊(duì)列。2.NSOperationQueue可以設(shè)置依賴關(guān)系 ~= GCD Group notify / GCD Group Wait / GCD Barrier。
3.可以設(shè)置最大并發(fā)數(shù)量(同時(shí)執(zhí)行的線程數(shù)) === GCD 信號(hào)量
示例代碼:

NSOperationQueue *operationQueue = [NSOperationQueue new];
    NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
        [self p_printThread:1];
        sleep(5);
    }];
    NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
        [self p_printThread:2];
        sleep(5);
    }];
    NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
        [self p_printThread:3];
        sleep(5);
    }];
    NSBlockOperation *blockOperation4 = [NSBlockOperation blockOperationWithBlock:^{
        [self p_printThread:4];
        sleep(5);
    }];
    
    // 2.NSOperationQueue可以設(shè)置依賴關(guān)系 ~=  GCD Group notify / GCD Group Wait / GCD Barrier
    [blockOperation1 addDependency:blockOperation2];
  
    // 3.可以設(shè)置最大并發(fā)數(shù)量(同時(shí)執(zhí)行的線程數(shù)) === GCD 信號(hào)量
    operationQueue.maxConcurrentOperationCount = 1;

    [operationQueue addOperations:@[blockOperation1, blockOperation2, blockOperation3, blockOperation4] waitUntilFinished:YES];

打印結(jié)果:

<NSThread: 0x600000078300>{number = 3, name = (null)}-------2

<NSThread: 0x600000078300>{number = 3, name = (null)}-------1

<NSThread: 0x60000007aa80>{number = 4, name = (null)}-------3

<NSThread: 0x60000007aa80>{number = 4, name = (null)}-------4

結(jié)論:運(yùn)行多次可以看出,每次只能執(zhí)行一個(gè)線程里的任務(wù)(這個(gè)類似信號(hào)量的控制);雖然任務(wù)1、2、3、4的順序不定,但是任務(wù)1總是在任務(wù)2的后面(類似group的notify和wait)。對(duì)比可以看出NSOperationQueue使用更方便一些,語(yǔ)法也更接近Objective-C。

最后編輯于
?著作權(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)容

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