一痹屹、定義與實(shí)現(xiàn)
放在最前:文章為本人學(xué)習(xí)隨筆章郁,若對您有幫助,不勝榮幸;若有錯漏歡迎評論區(qū)留言暖庄。
GCD 是一套異步執(zhí)行任務(wù)的技術(shù)之一聊替,是基于系統(tǒng)級的核心XNU內(nèi)核級上實(shí)現(xiàn)的,所以在iOS 開發(fā)中其性能是其他多線程技術(shù)無法與之相媲美的培廓。
那么GCD是如何實(shí)現(xiàn)的呢
GCD 的API全部為包含在libdispatch庫中的C語言函數(shù)惹悄。Dispatch Queue 通過結(jié)構(gòu)體和鏈表,被實(shí)現(xiàn)FIFO隊列肩钠。Pthread_workqueue是包含再Libc提供的pthreads API 中泣港。XNU內(nèi)核提供的workqueue 內(nèi)核持有的4中優(yōu)先級別的queue 與Dispatch Queue的優(yōu)先級類似,三個組件對應(yīng)優(yōu)先級關(guān)系如下圖:
二价匠、GCD 常用的 API
開發(fā)過程中我們要做的就是把定義好要執(zhí)行的任務(wù)并寫在block中并添加到適合的Dispatch Queue中当纱。
首先明確 Serial Dispatch Queue 和 Concurrent Dispatch Queue 的區(qū)別,前者是等待現(xiàn)在執(zhí)行中的任務(wù)處理結(jié)束即為串行隊列踩窖,后者是指不等待現(xiàn)在執(zhí)行中處理結(jié)束即為并行隊列坡氯;那么如何創(chuàng)建隊列呢如下:
/// 分別創(chuàng)建一個串行隊列與并發(fā)隊列
dispatch_queue_t serialQueue = dispatch_queue_create("com.gcd.dr", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.gcd.dr", DISPATCH_QUEUE_CONCURRENT);
創(chuàng)建好隊列以后就是怎么把任務(wù)添加到隊列里啦,那么追加任務(wù)又有兩種方式:同步執(zhí)行 dispatch_sync 和 異步執(zhí)行 dispatch_async 洋腮。如下示例:
? ?dispatch_async(serialQueue, ^{
? ? ? ? NSLog(@"打印1");
? ? });
這句是表示將打印任務(wù)非同步的追加到串行隊列中箫柳,不需要等待上一次任務(wù)執(zhí)行結(jié)束。
dispatch_sync(serialQueue,?^{
? ? ? ? NSLog(@"打印2");
? ? });
這句則是同步添加啥供,一旦調(diào)用同步那么會在打印2結(jié)束之后才能返回悯恍,但使用同步則要注意死鎖的情況 。
dispatch_queue_t queue=dispatch_get_main_queue();
dispatch_async(queue,^{
? ? dispatch_sync(queue,^{NSLog(@"Hello?");});
});
在主線程中執(zhí)行指定的Block等待Main Dispatch Queue 中要執(zhí)行的Block 執(zhí)行結(jié)束伙狐。
兩種特殊隊列
主隊列 Main Dispatch Queue / 全局隊列 Global Dispatch Queue
主隊列的執(zhí)行是在主線程的RunLoop 中執(zhí)行
全局隊列則是并行隊列涮毫,其有4個優(yōu)先級別:高、默認(rèn)鳞骤、低、后臺黍判。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)^{
? ? //全局隊列里執(zhí)行 數(shù)據(jù)計算類操作
? ? dispatch_async(dispatch_get_main_queue(),^{
? ? //主線程刷新UI操作
});
})
dispatch_set_target_queue
用于設(shè)定任務(wù)執(zhí)行優(yōu)先級
dispatch_queue_t globalBackGroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(serialQueue,globalBackGroundQueue);
第一個參數(shù)為要執(zhí)行的隊列豫尽;但第一個參數(shù)不建議使用主隊列或者全局隊列
dispatch_after?
延時處理線程
Dispatch Group
dispatch_queue_t firstQueue = dispatch_queue_create("first.com", DISPATCH_QUEUE_CONCURRENT);
? ? dispatch_queue_t secondQueue = dispatch_queue_create("second.com", DISPATCH_QUEUE_CONCURRENT);
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_group_notify(group, firstQueue, ^{
? ? ? ? NSLog(@"任務(wù)組處理完成調(diào)用 %@",[NSThreadcurrentThread]);
? ? });
? ? dispatch_group_async(group, firstQueue, ^{
? ? ? ? NSLog(@"吃");
? ? });
? ? dispatch_group_async(group, secondQueue, ^{
? ? ? ? NSLog(@"吃");
? ? });
dispatch_barrier_async 柵欄
dispatch_async(concurrentQueue, ^{
? ? ? ? NSLog(@"1---%@",[NSThread currentThread]);? ? ? // 打印當(dāng)前線程
? ? });
? ? dispatch_barrier_async(concurrentQueue, ^{
? ? ? ? NSLog(@"barrier---%@",[NSThread currentThread]);// 打印當(dāng)前線程
? ? });
?? ?dispatch_async(concurrentQueue, ^{
? ? ? ? NSLog(@"2---%@",[NSThread currentThread]);? ? ? // 打印當(dāng)前線程
? ? });
dispatch_apply
按指定次數(shù)執(zhí)行任務(wù)的次數(shù)的意思
?? ?dispatch_apply(10,concurrentQueue,^(size_tindex){
? ? ? ? NSLog(@"%@zu",index); ? ?});
? ? NSLog(@"done");
dispatch_suspend / dispatch_resume
任務(wù)的掛起與恢復(fù)
? ? dispatch_async(concurrentQueue,^{
? ? ? ? NSLog(@"1234");
? ? });
? ? dispatch_suspend(concurrentQueue);
? ? NSLog(@"暫停");
? ? dispatch_resume(concurrentQueue);
? ? NSLog(@"恢復(fù)");
Dispatch Semaphore
首先明確線程安全概念:如果你的代碼所在的進(jìn)程中有多個線程在同時運(yùn)行,而這些線程可能會同時運(yùn)行這段代碼顷帖。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的美旧,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的贬墩。
使用 semaphore 加鎖?dispatch_semaphore_wait 函數(shù)返回為0時刻安全第執(zhí)行需要排他控制的處理榴嗅。該處理結(jié)束時通過將其計數(shù)加1
?dispatch_semaphore_t semaphore =dispatch_semaphore_create(1);
? ? NSMutableArray *array=[NSMutableArray array];
? ? for(inti=0;i<1000;i++)
? ? {
? ? ? ? dispatch_async(concurrentQueue, ^{
? ? ? ? ? ? dispatch_set_context(semaphore,DISPATCH_TIME_FOREVER);
? ? ? ? ? ? [array addObject:@(i)];
? ? ? ? ? ? dispatch_semaphore_signal(semaphore);
? ? ? ? });
? ? }
dispatch_once
只執(zhí)行一次,常用于單例的生成
- (void)once {
? ? static dispatch_once_t onceToken;
? ? dispatch_once(&onceToken, ^{
? ? ? ? // 只執(zhí)行 1 次的代碼(這里面默認(rèn)是線程安全的)
? ? });}
Dispatch I/O
通過該方法讀寫文件陶舞,詳細(xì)??請見:http://www.reibang.com/p/33d6f52fe26b
更多api 請見 apple 官方文檔:https://developer.apple.com/documentation/dispatch?language=objc
參考:
1嗽测、http://www.reibang.com/p/2d57c72016c6
2、http://www.reibang.com/p/216228e153b0
3、<<Object-C 高級編程iOS 與OSX 多線程和內(nèi)存管理>>
那么GCD是如何實(shí)現(xiàn)的呢