隊(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é)果:

總結(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é)果就是:

如果設(shè)定信號(hào)值=3
dispatch_semaphore_create(3)
那么結(jié)果就是:

其實(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ù)的作用