理解這個(gè)概念之前,先拋出一個(gè)問(wèn)題
問(wèn)題描述:
假設(shè)現(xiàn)在系統(tǒng)有兩個(gè)空閑資源可以被利用,但同一時(shí)間卻有三個(gè)線程要進(jìn)行訪問(wèn),這種情況下,該如何處理呢?
或者
我們要下載很多圖片,并發(fā)異步進(jìn)行,每個(gè)下載都會(huì)開辟一個(gè)新線程,可是我們又擔(dān)心太多線程肯定CPU吃不消,那么我們這里也可以用信號(hào)量控制一下最大開辟線程數(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ì)使用。
3、那么就開頭提的問(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);
});
}
控制臺(tái)輸出:
2018-04-19 15:24:09.260057+0800 Barrier[71701:2876327] run task 2
2018-04-19 15:24:09.260057+0800 Barrier[71701:2876329] run task 1
2018-04-19 15:24:10.265626+0800 Barrier[71701:2876329] complete task 1
2018-04-19 15:24:10.265618+0800 Barrier[71701:2876327] complete task 2
2018-04-19 15:24:10.266074+0800 Barrier[71701:2876326] run task 3
2018-04-19 15:24:11.270587+0800 Barrier[71701:2876326] complete task 3
總結(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é)果就是:
2018-04-19 15:25:48.402966+0800 Barrier[71755:2879923] run task 1
2018-04-19 15:25:49.408142+0800 Barrier[71755:2879923] complete task 1
2018-04-19 15:25:49.408424+0800 Barrier[71755:2879910] run task 2
2018-04-19 15:25:50.413553+0800 Barrier[71755:2879910] complete task 2
2018-04-19 15:25:50.413772+0800 Barrier[71755:2879908] run task 3
2018-04-19 15:25:51.418006+0800 Barrier[71755:2879908] complete task 3
如果設(shè)定信號(hào)值=3
dispatch_semaphore_create(3)
那么結(jié)果就是:
2018-04-19 15:26:53.338567+0800 Barrier[71792:2883332] run task 3
2018-04-19 15:26:53.338567+0800 Barrier[71792:2883330] run task 1
2018-04-19 15:26:53.338567+0800 Barrier[71792:2883333] run task 2
2018-04-19 15:26:54.343147+0800 Barrier[71792:2883333] complete task 2
2018-04-19 15:26:54.343147+0800 Barrier[71792:2883330] complete task 1
2018-04-19 15:26:54.343192+0800 Barrier[71792:2883332] complete task 3
猜猜這里會(huì)如何輸出?
- (void)semaphore {
dispatch_group_t group = dispatch_group_create();
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queue = dispatch_queue_create("QueueName", DISPATCH_QUEUE_CONCURRENT);
for (int i=0; i<100; i++) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
NSLog(@"----%d", i);
sleep(2);
dispatch_semaphore_signal(semaphore);
});
}
NSLog(@"hello");
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"world");
}
通俗來(lái)說(shuō):
dispatch_semaphore_create(10)這會(huì)創(chuàng)建10個(gè)信號(hào)量。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);每執(zhí)行一次這個(gè)方法就會(huì)讓信號(hào)量減一,當(dāng)信號(hào)量小于零的時(shí)候,會(huì)處于一直等待的狀態(tài)。
dispatch_semaphore_signal(semaphore);每執(zhí)行一次這個(gè)方法,就會(huì)讓信號(hào)量加一,此時(shí)就表示有一個(gè)線程完成了,可以再重新開一個(gè)線程了。