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)一管理,所以效率很高竭业,而且形式上十分簡(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í)行一次的操作

});

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捞烟,一起剝皮案震驚了整個(gè)濱河市薄声,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌题画,老刑警劉巖默辨,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異苍息,居然都是意外死亡缩幸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門竞思,熙熙樓的掌柜王于貴愁眉苦臉地迎上來表谊,“玉大人,你說我怎么就攤上這事盖喷”欤” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵课梳,是天一觀的道長距辆。 經(jīng)常有香客問我余佃,道長,這世上最難降的妖魔是什么跨算? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任爆土,我火速辦了婚禮,結(jié)果婚禮上诸蚕,老公的妹妹穿的比我還像新娘步势。我一直安慰自己,他們只是感情好挫望,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布立润。 她就那樣靜靜地躺著狂窑,像睡著了一般媳板。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泉哈,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天蛉幸,我揣著相機(jī)與錄音,去河邊找鬼丛晦。 笑死奕纫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的烫沙。 我是一名探鬼主播匹层,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼锌蓄!你這毒婦竟也來了升筏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤瘸爽,失蹤者是張志新(化名)和其女友劉穎您访,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剪决,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灵汪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了柑潦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片享言。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖渗鬼,靈堂內(nèi)的尸體忽然破棺而出览露,到底是詐尸還是另有隱情,我是刑警寧澤乍钻,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布肛循,位于F島的核電站铭腕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏多糠。R本人自食惡果不足惜累舷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望夹孔。 院中可真熱鬧被盈,春花似錦、人聲如沸搭伤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怜俐。三九已至身堡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拍鲤,已是汗流浹背贴谎。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留季稳,地道東北人擅这。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像景鼠,于是被迫代替她去往敵國和親仲翎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容