GCD的奧秘

很多編程語(yǔ)言都會(huì)有多線程編程朗儒,拋開(kāi)多線程編程的復(fù)雜性颊乘,它確實(shí)能夠提升程序執(zhí)行的效率
参淹。特別是現(xiàn)在CPU都是多核,能夠充分發(fā)揮多核的優(yōu)勢(shì)也是一些編程語(yǔ)言的追求乏悄,比如說(shuō)golang浙值,
熟悉Golang或者java的開(kāi)發(fā)者,應(yīng)該都對(duì)多線程很熟悉檩小,然而在objc中开呐,使用GCD來(lái)進(jìn)行多線
程的編碼要來(lái)得更優(yōu)雅、更簡(jiǎn)單规求,下來(lái)就來(lái)揭開(kāi)其神秘面紗筐付。

API

開(kāi)發(fā)者要做的只是將想執(zhí)行的任務(wù)追加到適當(dāng)?shù)腄ispatch Queue中去。

dispatch_async(queue, ^{
    /*
     *想執(zhí)行的任務(wù)
     */
})

上面的代碼是使用GCD的一般格式阻肿,其中的queue分為兩種:

1. Serial Dispatch Queue (串行隊(duì)列)
2. Concurrent Dispatch Queue (并行隊(duì)列)

很好理解瓦戚,串行隊(duì)列中的任務(wù)會(huì)在一個(gè)線程中串行執(zhí)行,并行隊(duì)列中的任務(wù)會(huì)在多個(gè)線程中
并行執(zhí)行冕茅。那么如何得到這兩個(gè)隊(duì)列呢?

1. dispatch_queue_create

    dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.serialDispatchQueue", Operation)
    
上述Operation指示生成隊(duì)列的類(lèi)型蛹找,NULL和DISPATCH_QUEUE_SERIAL為串行姨伤,DISPATCH_QUEUE_CONCURRENT
為并行。

2. 獲取系統(tǒng)提供的隊(duì)列
_queue = dispatch_get_main_queue();
_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

第一個(gè)為主線程隊(duì)列庸疾,是串行的乍楚,后四個(gè)為全局并行隊(duì)列,可以通過(guò)參數(shù)來(lái)區(qū)分其優(yōu)先級(jí)

上面總結(jié)了GCD的最基本的用法届慈,當(dāng)然還有很多很實(shí)用的API徒溪,如下:

1. dispatch_set_target_queue
可以變更Queue的優(yōu)先級(jí),還可以將多個(gè)queue中的任務(wù)歸并到某一個(gè)queue中金顿。

2. dispatch_after
可以延遲某個(gè)任務(wù)的執(zhí)行臊泌,但是要注意:這里的延遲并不是任務(wù)在指定時(shí)間之后執(zhí)行,而是
延遲指定時(shí)間追加到隊(duì)列中去揍拆。

3. dispatch_group_async
如果想要追加到queue中的多個(gè)處理結(jié)束后進(jìn)行結(jié)束處理渠概,是使用dispatch_group的絕佳場(chǎng)景。
當(dāng)然將這些任務(wù)依次放入一個(gè)串行隊(duì)列中就可以解決問(wèn)題嫂拴,但是使用并行隊(duì)列時(shí)播揪,就需要
使用dispatch group了。

4. dispatch_barrier_asyc
dispatch_barrier允許在一個(gè)并發(fā)隊(duì)列中創(chuàng)建一個(gè)同步點(diǎn)筒狠,當(dāng)在并發(fā)隊(duì)列中遇到一個(gè)barrier猪狈,
它會(huì)等到在這個(gè)barrier之前提交的所有任務(wù)都執(zhí)行完畢之后,再執(zhí)行辩恼,而所有在barrier之
后提交的任務(wù)會(huì)等到barrier之后再執(zhí)行雇庙。

5. dispatch_semaphore
是GCD的同步信號(hào)量谓形,

上面所說(shuō)的都是異步GCD的API,當(dāng)然還有一些同步的API可以使用状共,也很重要套耕。

1. dispatch_apply
該函數(shù)按指定的次數(shù)將指定的block加入到指定的queue中去,并等待全部處理執(zhí)行結(jié)束峡继。
由于此API是同步的冯袍,所以一般在dispatch_async中使用它比較常見(jiàn)。

2. dispatch_once
函數(shù)保證在應(yīng)用程序中只執(zhí)行一次任務(wù)碾牌,普遍應(yīng)用于單例對(duì)象的初始化康愤。

3. dispatch_semaphore
GCD中的同步信號(hào)量,能夠比dispatch_group等提供更細(xì)粒度的同步控制舶吗,使用很廣泛征冷。

GCD使用案例

如果多個(gè)線程同時(shí)操作(讀寫(xiě))一個(gè)可變?nèi)萜鳎秃苡锌赡軙?huì)出現(xiàn)線程安全的問(wèn)題誓琼,當(dāng)一個(gè)線程
正在讀取時(shí)另一個(gè)線程正在修改就是一個(gè)不安全的行為检激,例如:

    - (void)addObject:(NSObject *)obj {
        if (obj) {
            [mutableArray addObject: obj];
            dispatch_async(dispatch_get_main_queue(), ^{
                [self postContentAddedNotification];
            });
        }
    }
    
    - (NSArray *)objects {
        return [NSArray arrayWithArray:mutableArray];
    }

如果使用GCD來(lái)改寫(xiě)這段不太安全的代碼,效果將是這樣的腹侣。

    - (void)addObject:(NSObject *)obj {
        if (obj) {
            dispatch_barrier_async(self.concurrentQueue, ^{
            [mutableArray addObject:obj];
            dispatch_async(dispatch_get_main_queue(), ^{
                [self postContentAddedNotification]; 
            });
        });
        }
    }
    
    - (NSArray *)objects {
        __block NSArray *array;
        dispatch_sync(self.concurrentQueue, ^{
            array = [NSArray arrayWithArray:_mutableArray];
        });
        return array;
    }
    

這段代碼中叔收,寫(xiě)入數(shù)據(jù)通過(guò)一個(gè)barrier來(lái)完成,因?yàn)閎arrierBlock永遠(yuǎn)不會(huì)和其它Block一
起執(zhí)行傲隶,所以保證了寫(xiě)安全饺律。在讀的時(shí)候,使用同步調(diào)用跺株,確保了函數(shù)返回复濒。在寫(xiě)客戶(hù)端代
碼的時(shí)候不會(huì)像服務(wù)端那樣變態(tài)地去考慮多線程問(wèn)題,但是在編碼過(guò)程中意識(shí)到哪些地方可能
會(huì)出錯(cuò)還是很重要的乒省。

死鎖

GCD相當(dāng)好用巧颈,但用不好就會(huì)死鎖,始終要記著這樣一句秘籍: 不要在串行隊(duì)列放dispatch_sync、
dispatch_apply袖扛,比如:

  • 案例一
dispatch_sync(dispatch_get_main_queue(), ^{

        NSLog(@"test");

    });
  • 案例二
//queue為串行隊(duì)列
dispatch_async(queue, ^{

    dispatch_sync(queue, ^{  
    
        NSLog(@"1"); // 任務(wù)1
        
    });
    
NSLog(@"2"); // 任務(wù)2

});

上文中兩個(gè)死鎖的例子對(duì)于dispatch_apply同樣適用洛二。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市攻锰,隨后出現(xiàn)的幾起案子晾嘶,更是在濱河造成了極大的恐慌,老刑警劉巖娶吞,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垒迂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡妒蛇,警方通過(guò)查閱死者的電腦和手機(jī)机断,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)楷拳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人吏奸,你說(shuō)我怎么就攤上這事欢揖。” “怎么了奋蔚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵她混,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我泊碑,道長(zhǎng)坤按,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任馒过,我火速辦了婚禮臭脓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腹忽。我一直安慰自己来累,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布窘奏。 她就那樣靜靜地躺著嘹锁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蔼夜。 梳的紋絲不亂的頭發(fā)上兼耀,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天压昼,我揣著相機(jī)與錄音求冷,去河邊找鬼。 笑死窍霞,一個(gè)胖子當(dāng)著我的面吹牛匠题,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播但金,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼韭山,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了冷溃?” 一聲冷哼從身側(cè)響起钱磅,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎似枕,沒(méi)想到半個(gè)月后盖淡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拢驾,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡峰伙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吞彤。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖浦辨,靈堂內(nèi)的尸體忽然破棺而出滔悉,到底是詐尸還是另有隱情,我是刑警寧澤心俗,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布傲武,位于F島的核電站,受9級(jí)特大地震影響另凌,放射性物質(zhì)發(fā)生泄漏谱轨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一吠谢、第九天 我趴在偏房一處隱蔽的房頂上張望土童。 院中可真熱鬧,春花似錦工坊、人聲如沸献汗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)罢吃。三九已至,卻和暖如春昭齐,著一層夾襖步出監(jiān)牢的瞬間尿招,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工阱驾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留就谜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓里覆,卻偏偏與公主長(zhǎng)得像丧荐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喧枷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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

  • 從哪說(shuō)起呢虹统? 單純講多線程編程真的不知道從哪下嘴。隧甚。 不如我直接引用一個(gè)最簡(jiǎn)單的問(wèn)題车荔,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,757評(píng)論 1 17
  • iOS中GCD的使用小結(jié) 作者dullgrass 2015.11.20 09:41*字?jǐn)?shù) 4996閱讀 20199...
    DanDanC閱讀 829評(píng)論 0 0
  • 本篇博客共分以下幾個(gè)模塊來(lái)介紹GCD的相關(guān)內(nèi)容: 多線程相關(guān)概念 多線程編程技術(shù)的優(yōu)缺點(diǎn)比較? GCD中的三種隊(duì)列...
    dullgrass閱讀 37,851評(píng)論 30 236
  • 本篇博客共分以下幾個(gè)模塊來(lái)介紹GCD的相關(guān)內(nèi)容: 多線程相關(guān)概念 多線程編程技術(shù)的優(yōu)缺點(diǎn)比較戚扳? GCD中的三種隊(duì)列...
    有夢(mèng)想的老伯伯閱讀 1,020評(píng)論 0 4
  • 2017年3月1日 做正確的事忧便,比正確做事更為重要。 ...
    窗外白楊閱讀 865評(píng)論 0 2