GCD實戰(zhàn)攻略

GCD是蘋果為多核并行運算提出的方案法瑟,可以更高效的利用CPU。但是更重要的是它使多任務(wù)處理更加高效蟹地。因為它會自動合理的運用多核CPU贯莺。并且自從GCD的內(nèi)存管理也加入ARC之后,它就能自動管理線程的生命周期柱衔。我們只需要把需要的操作(block)告訴它就可以了樊破。

凡說GCD,肯定要說兩個概念

任務(wù)和隊列唆铐,任務(wù)可以同步執(zhí)行和異步執(zhí)行哲戚,存放任務(wù)的隊列分為串行隊列和并行隊列。

一.任務(wù) (block)

就是咱們要執(zhí)行的操作艾岂,GCD中就是block,任務(wù)執(zhí)行在哪個線程由執(zhí)行方式來決定

1.同步執(zhí)行(sync)

會阻塞當(dāng)前任務(wù)所在的線程(同步線程),dispatch_sync(queue, ^(block))把block放到queue中在當(dāng)前線程執(zhí)行顺少。

2.異步執(zhí)行(async)

不會阻塞當(dāng)前任務(wù)所在的線程(異步線程),dispatch_async(queue, ^(block)),如果是串行隊列,則只開一個線程王浴,如果是并行隊列脆炎,則開多個線程。

所以說sync和async決定block在哪個線程中執(zhí)行

二.隊列 (queue)

存放任務(wù)的地方氓辣,負(fù)責(zé)調(diào)度任務(wù)(block)

1.串行隊列(SERIAL)顧名思義就是按順序執(zhí)行隊列中的任務(wù)秒裕,一個任務(wù)完成再執(zhí)行下一個任務(wù)。

主隊列:dispatch_get_main_queue 是一個特殊的串行隊列筛婉,運行在主線程中簇爆,UI相關(guān)操作都要在該隊列中執(zhí)行。

自定義串行隊列:dispatch_queue_create("標(biāo)識", DISPATCH_QUEUE_SERIAL)爽撒,最后一個參數(shù)可以為NULL,默認(rèn)創(chuàng)建的是串行隊列

2.并行隊列(CONCURRENT)就是很多任務(wù)并發(fā)執(zhí)行响蓉,其實GCD中的并行隊列也是根據(jù)FIFO的原則取出任務(wù)硕勿,不同的是取出任務(wù)后GCD會新開一個線程來執(zhí)行任務(wù)。

全局隊列:dispatch_get_global_queue(優(yōu)先級,0); 蘋果公開的全局并行隊列,一共有四個優(yōu)先級

自定義并行隊列:dispatch_queue_create("標(biāo)識", DISPATCH_QUEUE_CONCURRENT)


三.隊列和任務(wù)是怎么執(zhí)行的

GCD的基本概念雖然不多枫甲,但是用起來還是需要理解的深刻一些源武,比如任務(wù)在不同的隊列類別里用不同的方式執(zhí)行會造成什么樣的結(jié)果扼褪,接下來咱們就來一項一項說。

1.串行隊列同步執(zhí)行?

2.串行隊列異步執(zhí)行

串行隊列同步/異步執(zhí)行任務(wù)

執(zhí)行結(jié)果:


串行隊列執(zhí)行結(jié)果

1-4為串行隊列同步執(zhí)行

5-6為串行隊列異步執(zhí)行

可以看出來:1-4在當(dāng)前線程一個一個執(zhí)行,5-6新開了一個線程一個一個執(zhí)行(如果串行隊列為主隊列粱栖,則在主線程中執(zhí)行)

3.并行隊列同步執(zhí)行 4.并行隊列異步執(zhí)行

并行隊列同步/異步執(zhí)行任務(wù)

執(zhí)行結(jié)果:

并行隊列執(zhí)行結(jié)果

1-4為并行隊列同步執(zhí)行

5-6為并行隊列異步執(zhí)行

可以看出來:1-4在當(dāng)前線程一個一個執(zhí)行话浇,5-6新開了多個線程并發(fā)執(zhí)行

四.實戰(zhàn)場景

理解了任務(wù)、隊列的運行規(guī)則闹究,下面就來看看實際項目中在何種場景下運用GCD

1.運用dispatch_async來避免一些耗時的任務(wù)阻塞主線程(卡死界面).

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

? ? ? ? NSLog(@"耗時的操作讀取數(shù)據(jù)庫幔崖,網(wǎng)絡(luò)操作等");

? ? ? ? dispatch_sync(dispatch_get_main_queue(), ^{

? ? ? ? ? ? ? NSLog(@"操作完成_刷新UI在:%@",i,[NSThread currentThread]);

? ? ? ? });

});

這里可能有人會問:回到主線程的操作,dispatch_sync和dispatch_async有什么區(qū)別渣淤?

大家可以想想這個問題赏寇,如果理解了前面說的隊列和任務(wù),你應(yīng)該知道結(jié)果价认,文章后面還會提到嗅定。

2.運用dispatch_apply進(jìn)行快速迭代.

如果是串行隊列,dispatch_apply和for是一樣的用踩,

如果運用在并發(fā)隊列渠退,那么dispatch_apply就會并發(fā)的執(zhí)行任務(wù)(block),大大的提高遍歷速度脐彩。

dispatch_apply


dispatch_apply執(zhí)行結(jié)果

> 兩種方法各循環(huán)100000次碎乃,for耗時32.9秒,apply耗時19.4秒

> 效率提高了40%多丁屎。

有人說可以在for循環(huán)里面用dispatch_async開啟子線程執(zhí)行任務(wù)荠锭,的確可以,但是如果開啟的子線程多了晨川,很有可能線程爆炸造成死鎖等情況证九。而GCD會管理并發(fā),所以apply還能避免線程爆炸的問題共虑,實在是居家旅行愧怜、殺人滅口,必備良藥妈拌。

3.dispatch_group 調(diào)度組

開發(fā)中我們經(jīng)常會遇到這樣的需求:同時調(diào)用多個接口拥坛,所有接口返回后再刷新界面。如果不用調(diào)度組的話尘分,應(yīng)該怎么做猜惋?大部分人都會把這幾個接口串行起來,等最后一個接口返回再執(zhí)行刷新界面的方法培愁,這樣做的話如果其中一個接口返回失敗著摔,那么整個頁面就無法刷新了。還有的同學(xué)每個接口回來都刷新一次界面定续,這樣會造成頁面閃爍谍咆,嚴(yán)重的話禾锤,并發(fā)調(diào)用同時回來結(jié)果操作同一數(shù)據(jù)源,還有可能造成崩潰摹察。

這時無疑用GCD調(diào)度組是最好的解決方法恩掷。調(diào)度組會在組里所有的任務(wù)執(zhí)行完畢后發(fā)送一個通知告訴我們,組內(nèi)的任務(wù)全部執(zhí)行完畢供嚎。

接收通知的方式有兩種黄娘,

同步執(zhí)行的dispatch_block_wait,會阻塞當(dāng)前線程并等待之前的任務(wù)全部執(zhí)行完或超時再執(zhí)行wait中隊列里的任務(wù)

異步執(zhí)行的dispatch_group_notify查坪,作用和wait一樣寸宏,但是是異步執(zhí)行的,所以不會阻塞當(dāng)前線程

dispatch_group_enter和dispatch_group_leave可以手動管理group中的任務(wù)計數(shù)偿曙,enter為+1氮凝,leave為-1,當(dāng)計數(shù)為0時望忆,才會進(jìn)入wait或notify中的任務(wù)

具體執(zhí)行看代碼:這里用after延遲提交任務(wù)(block)的做法來模擬調(diào)用接口時的情景罩阵。


調(diào)度組方法執(zhí)行結(jié)果

以上代碼中創(chuàng)建了一個調(diào)度組group,并且指定調(diào)度組中的任務(wù)在全局隊列中運行启摄。在執(zhí)行結(jié)果中可以看到稿壁,全局隊列中先執(zhí)行了任務(wù)2和任務(wù)1(強(qiáng)制停止了1秒),因為wait會在當(dāng)前線程等待任務(wù)1歉备,2都完成之后才執(zhí)行傅是,所以wait執(zhí)行完后再執(zhí)行任務(wù)3,4蕾羊,這里用了手動計數(shù)的方法控制任務(wù)計數(shù)喧笔,當(dāng)3,4都執(zhí)行完后龟再,計數(shù)歸0书闸,最后計入notify的任務(wù),當(dāng)我們需要同時并發(fā)執(zhí)行多個接口之后再執(zhí)行某項操作時利凑,調(diào)度組非常實用浆劲。

4.GCD中容易遇到的死鎖問題

GCD的任務(wù)和隊列都是在線程中運行的,所以頻繁的操作線程如果不注意會很容易造成死鎖問題哀澈,所謂死鎖牌借,就是指兩個線程互相等待對方完成某項操作,導(dǎo)致線程卡死割按,當(dāng)然歸根結(jié)底是對任務(wù)和隊列的運行方式理解的還不夠徹底走哺,下面列舉一些容易造成死鎖的現(xiàn)象,coding中要格外注意哲虾。

案例1:最簡單的死鎖現(xiàn)象

控制臺只輸出了1

控制臺:

1.

我們來分析一下堆棧信息丙躏,根據(jù)FIFO的原則,任務(wù)1 - 同步線程-任務(wù)3-任務(wù)2

因為同步線程阻塞了主線程束凑,所以任務(wù)2等待任務(wù)3執(zhí)行晒旅,任務(wù)3又等待任務(wù)2,造成死鎖汪诉,程序卡死废恋。

這時如果我們再稍微復(fù)雜一些呢


如果大家理解了這個案例,相信自己就能回答出來了


案例2:串行隊列中同步執(zhí)行一個并行隊列中的任務(wù)


同步運行全局隊列中的任務(wù)


控制臺:

1

2

3

這個比較好理解扒寄,在主線程中打印1鱼鼓,這時同步線程在全局隊列里面執(zhí)行2,不會像1一樣把任務(wù)2直接加在主隊列隊尾该编,所以不存在2迄本,3相互等待的情況,而是同步線程阻塞了主線程后等待任務(wù)2執(zhí)行完畢后课竣,順序執(zhí)行3.

案例3:異步線程執(zhí)行后回到同步線程執(zhí)行


是不是很眼熟,這就是4.實戰(zhàn)場景中的第一個案例,我們當(dāng)然不是要演示這個嘉赎,繼續(xù)看下圖兩張圖


控制臺:

1

8

2

3

4

5

6

7

控制臺:

1

8

2

7

3

4

5

6


控制臺:


1,4順序不一定

分析:輸出0后于樟,就是異步線程公条,所以任務(wù)4不用等待,1迂曲,4執(zhí)行順序不一定靶橱。任務(wù)4完成后,接著是一個阻塞線程的同步任務(wù)5路捧,但是加入到全局隊列的異步線程不受影響关霸,繼續(xù)執(zhí)行1后面的同步線程中的任務(wù)2,并且任務(wù)3需要等任務(wù)2完成后才能執(zhí)行鬓长。但是這時主線程已經(jīng)被一個同步線程的任務(wù)5谒拴,和6死鎖,所以任務(wù)2也無法執(zhí)行涉波。

總結(jié)

GCD除了上面說的這些英上,只要理解了他的運行方式,可以靈活的組合出很多用法啤覆,當(dāng)然這篇文章只是說了GCD的鳳毛麟角苍日,NSOperation和NSOperationQueue還沒有提到,先理解了GCD窗声,咱們下次說NSOperation和NsOperationQueue相恃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市笨觅,隨后出現(xiàn)的幾起案子拦耐,更是在濱河造成了極大的恐慌耕腾,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杀糯,死亡現(xiàn)場離奇詭異扫俺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)固翰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門狼纬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人骂际,你說我怎么就攤上這事疗琉。” “怎么了歉铝?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵盈简,是天一觀的道長。 經(jīng)常有香客問我犯戏,道長送火,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任先匪,我火速辦了婚禮种吸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘呀非。我一直安慰自己坚俗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布岸裙。 她就那樣靜靜地躺著猖败,像睡著了一般。 火紅的嫁衣襯著肌膚如雪降允。 梳的紋絲不亂的頭發(fā)上恩闻,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音剧董,去河邊找鬼幢尚。 笑死,一個胖子當(dāng)著我的面吹牛翅楼,可吹牛的內(nèi)容都是我干的尉剩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼毅臊,長吁一口氣:“原來是場噩夢啊……” “哼理茎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤皂林,失蹤者是張志新(化名)和其女友劉穎朗鸠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體式撼,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡童社,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了著隆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡呀癣,死狀恐怖美浦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情项栏,我是刑警寧澤浦辨,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站沼沈,受9級特大地震影響流酬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜列另,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狠持,春花似錦函似、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至眨八,卻和暖如春腺兴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背廉侧。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工页响, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伏穆。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓拘泞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親枕扫。 傳聞我的和親對象是個殘疾皇子陪腌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

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