-
延時(shí)執(zhí)行(dispatch_after)
需要注意的是:dispatch_after函數(shù)并不是在指定時(shí)間之后才開始執(zhí)行處理,而是在指定時(shí)間之后將任務(wù)追加到隊(duì)列中蛹屿。嚴(yán)格來說肴颊,這個(gè)時(shí)間并不是絕對(duì)準(zhǔn)確的宰译,但想要大致延遲執(zhí)行任務(wù)迎变,dispatch_after函數(shù)是很有效宁仔。dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后異步追加任務(wù)代碼到主隊(duì)列 NSLog(@"----執(zhí)行任務(wù)---當(dāng)前線程%@",[NSThread currentThread]); });
-
只執(zhí)行一次(dispatch_once)
通常在創(chuàng)建單例時(shí)使用蓖乘,多線程環(huán)境下也能保證線程安全static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"----只執(zhí)行一次的任務(wù)---當(dāng)前線程%@",[NSThread currentThread]); });
-
重復(fù)執(zhí)行(dispatch_apply)
快速遍歷方法锤悄,可以替代for循環(huán)的函數(shù)。dispatch_apply按照指定的次數(shù)將指定的任務(wù)追加到指定的隊(duì)列中嘉抒,并等待全部隊(duì)列執(zhí)行結(jié)束零聚。你可以把他理解成for循環(huán)遍歷,其優(yōu)勢(shì)是可以充分利用多核的性能众眨。//并發(fā)隊(duì)列 dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //串行隊(duì)列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue", DISPATCH_QUEUE_SERIAL); //你可以試試并發(fā)和串行的區(qū)別 dispatch_apply(10, globalQueue, ^(size_t index) { NSLog(@"執(zhí)行第%zd次的任務(wù),%@",index,[NSThread currentThread]); [NSThread sleepForTimeInterval:1]; });
-
隊(duì)列組(dispatch_group)
比如當(dāng)我們遇到需要異步下載3張圖片握牧,都下載完之后再拼接成一個(gè)整圖的時(shí)候,就需要用到gcd隊(duì)列組娩梨。
dispatch_group_enter 標(biāo)志著一個(gè)任務(wù)追加到 group沿腰,執(zhí)行一次,相當(dāng)于 group 中未執(zhí)行完畢任務(wù)數(shù)+1
dispatch_group_leave 標(biāo)志著一個(gè)任務(wù)離開了 group狈定,執(zhí)行一次颂龙,相當(dāng)于 group 中未執(zhí)行完畢任務(wù)數(shù)-1。
當(dāng) group 中未執(zhí)行完畢任務(wù)數(shù)為0的時(shí)候纽什,才會(huì)使dispatch_group_wait解除阻塞措嵌,以及執(zhí)行追加到dispatch_group_notify中的任務(wù)。//創(chuàng)建隊(duì)列組 dispatch_group_t group = dispatch_group_create(); //全局串行隊(duì)列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_enter(group); dispatch_async(queue, ^{ // 第一個(gè)任務(wù) [NSThread sleepForTimeInterval:2]; NSLog(@"執(zhí)行第一個(gè)任務(wù)"); dispatch_group_leave(group); }); dispatch_group_enter(group); dispatch_async(queue, ^{ // 第二個(gè)任務(wù) [NSThread sleepForTimeInterval:2]; NSLog(@"執(zhí)行第二個(gè)任務(wù)"); dispatch_group_leave(group); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"執(zhí)行最后的匯總?cè)蝿?wù)"); });
-
信號(hào)量(dispatch_semaphore)
用來設(shè)置當(dāng)前隊(duì)列的最大并發(fā)數(shù)芦缰。
信號(hào)量就3個(gè)方法企巢,1創(chuàng)建信號(hào)數(shù)量,2wait让蕾,3signal浪规。信號(hào)量就類似交通信號(hào)燈或听。
dispatch_semaphore_wait判讀當(dāng)前信號(hào)量。為0則紅燈禁止通行,等待信號(hào)量大于0后放行笋婿。放行后對(duì)信號(hào)量-1誉裆;
dispatch_semaphore_signal與wait成對(duì)出現(xiàn)。表示任務(wù)已結(jié)束缸濒。對(duì)信號(hào)量+1足丢;//創(chuàng)建信號(hào)量為2 dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); //全局并發(fā)隊(duì)列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //任務(wù)1 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"----開始執(zhí)行第一個(gè)任務(wù)---"); [NSThread sleepForTimeInterval:2]; NSLog(@"----結(jié)束執(zhí)行第一個(gè)任務(wù)---",); dispatch_semaphore_signal(semaphore); }); //任務(wù)2 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"----開始執(zhí)行第二個(gè)任務(wù)---"); [NSThread sleepForTimeInterval:1]; NSLog(@"----結(jié)束執(zhí)行第二個(gè)任務(wù)---"); dispatch_semaphore_signal(semaphore); }); //任務(wù)3 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"----開始執(zhí)行第三個(gè)任務(wù)---",); [NSThread sleepForTimeInterval:2]; NSLog(@"----結(jié)束執(zhí)行第三個(gè)任務(wù)---"); dispatch_semaphore_signal(semaphore); });
-
柵欄(dispatch_barrier)
在柵欄前放入隊(duì)列的操作執(zhí)行完后,再執(zhí)行柵欄后放入隊(duì)列的操作庇配。當(dāng)然也可以用Dispatch Group實(shí)現(xiàn)相同功能,只是比較而言斩跌,dispatch_barrier_async會(huì)更加順滑。需要注意的是:使用的隊(duì)列應(yīng)該是你自己創(chuàng)建的并發(fā)隊(duì)列讨永。不可以是系統(tǒng)隊(duì)列或者串行隊(duì)列滔驶,具體原因,讀者可以思考一下卿闹。//全局并發(fā)隊(duì)列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"柵欄前的任務(wù)"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"柵欄前的任務(wù)"); }); //柵欄 dispatch_barrier_async(queue, ^{ // 等待處理 [NSThread sleepForTimeInterval:2]; NSLog(@"-柵欄等待-"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"柵欄后的任務(wù)"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"柵欄后的任務(wù)"); });
-
掛起(dispatch_suspend)揭糕、恢復(fù)(dispatch_resume)隊(duì)列
簡(jiǎn)單來說,就是可以暫停锻霎、恢復(fù)隊(duì)列上的任務(wù)著角。但是這里的“掛起”,并不能保證可以立即停止隊(duì)列上正在運(yùn)行的任務(wù)旋恼,也就是如果掛起之前已經(jīng)有隊(duì)列中的任務(wù)在進(jìn)行中吏口,那么該任務(wù)依然會(huì)被執(zhí)行完畢//串行隊(duì)列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{ // 執(zhí)行第一個(gè)任務(wù) NSLog(@"----執(zhí)行第一個(gè)任務(wù)---"); }); dispatch_async(queue, ^{ // 執(zhí)行第二個(gè)任務(wù) NSLog(@"開始執(zhí)行第二個(gè)任務(wù)"); [NSThread sleepForTimeInterval:5]; NSLog(@"結(jié)束執(zhí)行第二個(gè)任務(wù)"); }); dispatch_async(queue, ^{ // 執(zhí)行第三個(gè)任務(wù) NSLog(@"開始執(zhí)行第三個(gè)任務(wù)"); [NSThread sleepForTimeInterval:5]; NSLog(@"結(jié)束執(zhí)行第三個(gè)任務(wù)"); }); //此時(shí)發(fā)現(xiàn)意外情況,掛起隊(duì)列 NSLog(@"suspend"); dispatch_suspend(queue); //掛起3秒之后冰更,恢復(fù)正常 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //恢復(fù)隊(duì)列 NSLog(@"3秒后恢復(fù)resume"); dispatch_resume(queue); });
-
定時(shí)器
GCD的定時(shí)器比NSTimer有更高的進(jìn)度产徊,而且避免了NSTimer的三大缺陷(RunLoop,不能跨越線程操作蜀细,內(nèi)存泄漏風(fēng)險(xiǎn))dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //創(chuàng)建定時(shí)器 self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); //構(gòu)建參數(shù)舟铜。設(shè)置從何時(shí)開始/設(shè)置時(shí)間間隔 dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, 0* NSEC_PER_SEC), 1.0 * NSEC_PER_SEC, 0); //要執(zhí)行的時(shí)間 dispatch_source_set_event_handler(self.timer, ^{ NSLog(@"多久打印一次"); }); //運(yùn)行GSD dispatch_resume(self.timer); //取消定時(shí)器 //dispatch_cancel(self.timer); self.timer = nil;
總結(jié)
本節(jié)我們主要簡(jiǎn)單的梳理了GCD的一些實(shí)用API,可以發(fā)現(xiàn)這些API是純c語言的奠衔,并且相關(guān)API繁多谆刨,在實(shí)際編碼過程中即使有代碼提示,往往編碼效率還是比較慢的归斤,造成一定的使用門檻痊夭。當(dāng)然,你也通過自定義代碼塊來提升效率脏里。但是我們能不能通過封裝她我,來實(shí)現(xiàn)簡(jiǎn)單易用的GCD呢?下一節(jié)我們來談一談這個(gè)問題,CGD的封裝番舆。