GCD(Grand Center Dispatch)是異步執(zhí)行任務(wù)的技術(shù)之一。開發(fā)者只需要定義想要執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中米母,GCD就能生成必要的線程并計(jì)劃執(zhí)行任務(wù)枕稀。
GCD的優(yōu)點(diǎn):GCD負(fù)責(zé)生成線程并計(jì)劃執(zhí)行任務(wù)弟翘,其線程管理是作為系統(tǒng)的一部分來實(shí)現(xiàn)的命斧,因此可統(tǒng)一管理,所以效率很高竭业,而且形式上十分簡(jiǎn)潔智润。
GCD的API:
開發(fā)者要做的只是定義想執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue( 等待執(zhí)行的隊(duì)列)
//^ caret
dispatch_async(queue, ^{
//這個(gè)Block是想執(zhí)行的任務(wù)之一
長時(shí)間處理
長時(shí)間處理結(jié)束后,回到主線程
dispatch_async(dispatch_get_main_queue(), ^{
//例如用戶界面更新等只可以在主線程可以執(zhí)行的處理
});
});
兩種Dispatch Queue
Serial?Dispatch Queue:按照任務(wù)(塊)加入到queue的順序未辆,一個(gè)一個(gè)的執(zhí)行(先進(jìn)先出)窟绷,用于不能改變執(zhí)行順序或不想并發(fā)執(zhí)行任務(wù)時(shí)。但是可以創(chuàng)建多個(gè)Serial?Dispatch Queu咐柜,每一個(gè)只有一個(gè)任務(wù)在執(zhí)行兼蜈,則依然有很多個(gè)任務(wù)在執(zhí)行攘残。(不能大量生成Serial?Dispatch Queu,因?yàn)檫@樣會(huì)消耗大量內(nèi)存饭尝,引起大量的上下文切換肯腕,大幅度降低系統(tǒng)的響應(yīng)性能献宫。)
Concurrent?Dispatch Queue:并行處理多個(gè)任務(wù)(塊)钥平,并行執(zhí)行的數(shù)量取決于系統(tǒng)的狀態(tài)
1、通過API生成Dispatch Queue:dispatch_queue_create
dispatch_queue_t mySerialDispatchQueue =dispatch_queue_create("com.mySerialDispatchQueue.GCD",NULL);
dispatch_queue_t myConcurrentDispatchQueue =dispatch_queue_create("com.myConcurrentDispatchQueue.GCD",DISPATCH_QUEUE_CONCURRENT);
(dispatch_release(mySerialDispatchQueue);)
該函數(shù)的第一個(gè)參數(shù)是queue的名稱姊途,可以用NULL涉瘾,但是署名后對(duì)調(diào)試很有幫助。
第二個(gè)參數(shù)為queue的類型捷兰,返回值均為dispatch_queue_t類型立叛。
最低sdk版本>=ios6.0來說,GCD對(duì)象已經(jīng)納入了ARC的管理范圍,我們就不需要再手工調(diào)用 dispatch_release了,否則的話,在sdk<6.0的時(shí)候,即使我們開啟了ARC,這個(gè)宏OS_OBJECT_USE_OBJC 也是沒有的,也就是說這個(gè)時(shí)候,GCD對(duì)象還必須得自己管理,生成的Dispatch Queue必須由程序員負(fù)責(zé)釋放。
2贡茅、獲取系統(tǒng)提供的Dispatch Queue
Main Dispatch Queue和Global Dispatch Queue
追加到Main Dispatch Queue的處理在主線程的RunLoop中執(zhí)行:
dispatch_get_main_queue() ?//獲取Main Dispatch Queue
Global Dispatch Queue是所有應(yīng)用程序都能夠使用的Concurrent Dispatch秘蛇,它有四個(gè)優(yōu)先級(jí):High、Default顶考、Low赁还、Background Priority。
dispatch_queue_t globalDispatchQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);//獲取
其余API:
dispatch_set_target_queue:修改自己生成的Dispatch Queue的優(yōu)先級(jí)
dispatch_queue_create生成默認(rèn)優(yōu)先級(jí)
//修改優(yōu)先級(jí)
dispatch_queue_t mySerialDispatchQueue =dispatch_queue_create("com.mySerialDispatchQueue.GCD",NULL);
dispatch_queue_t globalDispatchQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueue);
注意:如果在多個(gè)Serial Dispatch Queue使用該函數(shù)指定目標(biāo)為某一個(gè)Serial Dispatch Queue驹沿,那么原本應(yīng)并行執(zhí)行的多個(gè)Serial Dispatch Queue艘策,在目標(biāo)Serial Dispatch Queue上只能同時(shí)執(zhí)行一個(gè)處理。這可用于防止并行執(zhí)行渊季。
dispatch_after:將任務(wù)延遲加載到Dispatch Queue
dispatch_time_ttime =dispatch_time(DISPATCH_TIME_NOW,3ull *NSEC_PER_SEC);
dispatch_after(time,dispatch_get_main_queue(), ^{
NSLog(@"delay");
});
值得注意的是:
上面源代碼是在3秒后將block加到Main Dispatch Queue朋蔫。因?yàn)镸ain Dispatch Queue在主線程的RunLoop中執(zhí)行,所以比如每隔1/60秒執(zhí)行的RunLoop中却汉,Block最快在3秒后執(zhí)行驯妄,最慢在3+1/60秒執(zhí)行。
dispatch_group_async:用于Concurrent Dispatch Queue或者多個(gè)Dispatch Queue中的全部處理結(jié)束后執(zhí)行結(jié)束處理合砂。
dispatch_group_tgroup =dispatch_group_create();
dispatch_group_async(group, myConcurrentDispatchQueue, ^{
NSLog(@"1");
});
dispatch_group_async(group, myConcurrentDispatchQueue, ^{
NSLog(@"2");
});
dispatch_group_async(group, myConcurrentDispatchQueue, ^{
NSLog(@"3");
});
dispatch_group_async(group, myConcurrentDispatchQueue, ^{
NSLog(@"4");
});
dispatch_group_async(group, myConcurrentDispatchQueue, ^{
NSLog(@"5");
});
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
NSLog(@"finish");
});
finish一定是最后執(zhí)行的青扔。當(dāng)1、2既穆、3赎懦、4、5執(zhí)行完畢后幻工,dispatch_group_notify將Block(finish)添加到Main Dispatch Queue中励两。
指定的Block屬于指定的group dispatch_time_t waitTime =dispatch_time(DISPATCH_TIME_NOW,1ull *NSEC_PER_SEC);
longresault =dispatch_group_wait(group, waitTime);
if(resault ==0) {
/*
*屬于Dispatch Group的全部處理執(zhí)行結(jié)束
*/
}else{
}
該方法可以檢查執(zhí)行是否全部結(jié)束。
dispatch_barrier_async:用于將Dispatch Queue中的并行操作處理完后囊颅,再追加当悔。
可實(shí)現(xiàn)高效率的數(shù)據(jù)庫訪問和文件訪問傅瞻。
dispatch_queue_tbarrierQueue =dispatch_queue_create("com.barrierQueue.GCD",DISPATCH_QUEUE_CONCURRENT);
dispatch_async(barrierQueue, ^{
NSLog(@"r1");
});
dispatch_async(barrierQueue, ^{
NSLog(@"r2");
});
dispatch_barrier_async(barrierQueue, ^{
NSLog(@"w1");
});
dispatch_async(barrierQueue, ^{
NSLog(@"r3");
});
dispatch_async(barrierQueue, ^{
NSLog(@"r4");
});
執(zhí)行順序:r1、r2或r2盲憎、r1---w1---- ?r3嗅骄、r4或r4、r3(w1一定在r1和r2之后執(zhí)行饼疙,在r3和r4之前執(zhí)行)
dispatch_sync:同步即是將指定的Block追加到Dispatch Queue中并等待Block執(zhí)行結(jié)束才繼續(xù)執(zhí)行溺森。
dispatch_queue_tsyncQueue =dispatch_queue_create("my.syncQueue.queue",DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(syncQueue, ^{
NSLog(@"s2");
[NSThreadsleepForTimeInterval:10];
NSLog(@"s3");
});
NSLog(@"s4");
一定最后執(zhí)行s4
這個(gè)方法很容易出現(xiàn)死鎖問題:
dispatch_queue_tqueue =dispatch_get_main_queue();
dispatch_sync(queue, ^{NSLog(@"Hello");});
這導(dǎo)致了等待Main Dispatch Queue執(zhí)行完畢后再執(zhí)行Main Dispatch Queue的問題。
dispatch_apply:按指定的次數(shù)將所有Block追加到Dispatch Queue中窑眯,這些Block異步執(zhí)行屏积,等所有Block全部執(zhí)行完畢后再往下執(zhí)行。推薦在dispatch_async中使用磅甩。
NSArray*a =@[@"1",@"2",@"3",@"4"];
dispatch_queue_tapplyQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_apply([acount], applyQueue, ^(size_tindex){
NSLog(@"a:%@",a[index]);
});
NSLog(@"apply Done”);//最后執(zhí)行
//掛起指定的queueu
dispatch_suspend(globalDispatchQueue);
//恢復(fù)指定的queue
dispatch_resume(globalDispatchQueue);
這些函數(shù)對(duì)已經(jīng)執(zhí)行的處理沒有影響炊林,刮起后尚未執(zhí)行的處理在此之后停止執(zhí)行,而恢復(fù)使得這些處理繼續(xù)進(jìn)行卷要。
dispatch_semaphore_t:信號(hào)量機(jī)制渣聚,保證訪問資源的線程個(gè)數(shù)
dispatch_queue_tsemaphoreQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
NSMutableArray*mutableArray = [NSMutableArrayarray];
for(inti =0; i<100000; i++) {
dispatch_async(semaphoreQueue, ^{
[mutableArrayaddObject:[NSNumbernumberWithInt:i]];
});
}
容易由內(nèi)存錯(cuò)誤導(dǎo)致應(yīng)用程序異常結(jié)束的概率極高
dispatch_queue_tsemaphoreQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//計(jì)數(shù)初始為1,保證可以訪問的線程同時(shí)只有一個(gè)
dispatch_semaphore_tsemaphore =dispatch_semaphore_create(1);
NSMutableArray*mutableArray = [NSMutableArrayarray];
for(inti =0; i<100000; i++) {
dispatch_async(semaphoreQueue, ^{
//一直等待僧叉、直到Dispatch Semaphore的計(jì)數(shù)大于等于1
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
//由于初始值為1奕枝,上面的函數(shù)執(zhí)行后計(jì)數(shù)為0,只有一個(gè)線程繼續(xù)往下訪問彪标,
//這和操作系統(tǒng)用信號(hào)量機(jī)制的原理是一樣的倍权。
[mutableArrayaddObject:[NSNumbernumberWithInt:i]];
dispatch_semaphore_signal(semaphore);
});
}
dispatch_once:保證在應(yīng)用程序中只執(zhí)行一次,生成單例對(duì)象時(shí)使用
dispatch_once_t pred;
dispatch_once(&pred, ^{
//只執(zhí)行一次的操作
});