GCD詳解

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)一管理,所以效率很高,而且形式上十分簡潔。

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í)行一次的操作

});

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容