GCD實戰攻略

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

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

任務和隊列,任務可以同步執行和異步執行,存放任務的隊列分為串行隊列和并行隊列。

一.任務 (block)

就是咱們要執行的操作,GCD中就是block,任務執行在哪個線程由執行方式來決定

1.同步執行(sync)

會阻塞當前任務所在的線程(同步線程),dispatch_sync(queue, ^(block))把block放到queue中在當前線程執行。

2.異步執行(async)

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

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

二.隊列 (queue)

存放任務的地方,負責調度任務(block)

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

主隊列:dispatch_get_main_queue 是一個特殊的串行隊列,運行在主線程中,UI相關操作都要在該隊列中執行。

自定義串行隊列:dispatch_queue_create("標識", DISPATCH_QUEUE_SERIAL),最后一個參數可以為NULL,默認創建的是串行隊列

2.并行隊列(CONCURRENT)就是很多任務并發執行,其實GCD中的并行隊列也是根據FIFO的原則取出任務,不同的是取出任務后GCD會新開一個線程來執行任務。

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

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


三.隊列和任務是怎么執行的

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

1.串行隊列同步執行?

2.串行隊列異步執行

串行隊列同步/異步執行任務

執行結果:


串行隊列執行結果

1-4為串行隊列同步執行

5-6為串行隊列異步執行

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

3.并行隊列同步執行 4.并行隊列異步執行

并行隊列同步/異步執行任務

執行結果:

并行隊列執行結果

1-4為并行隊列同步執行

5-6為并行隊列異步執行

可以看出來:1-4在當前線程一個一個執行,5-6新開了多個線程并發執行

四.實戰場景

理解了任務、隊列的運行規則,下面就來看看實際項目中在何種場景下運用GCD

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

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

? ? ? ? NSLog(@"耗時的操作讀取數據庫,網絡操作等");

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

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

? ? ? ? });

});

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

大家可以想想這個問題,如果理解了前面說的隊列和任務,你應該知道結果,文章后面還會提到。

2.運用dispatch_apply進行快速迭代.

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

如果運用在并發隊列,那么dispatch_apply就會并發的執行任務(block),大大的提高遍歷速度。

dispatch_apply


dispatch_apply執行結果

> 兩種方法各循環100000次,for耗時32.9秒,apply耗時19.4秒

> 效率提高了40%多。

有人說可以在for循環里面用dispatch_async開啟子線程執行任務,的確可以,但是如果開啟的子線程多了,很有可能線程爆炸造成死鎖等情況。而GCD會管理并發,所以apply還能避免線程爆炸的問題,實在是居家旅行、殺人滅口,必備良藥。

3.dispatch_group 調度組

開發中我們經常會遇到這樣的需求:同時調用多個接口,所有接口返回后再刷新界面。如果不用調度組的話,應該怎么做?大部分人都會把這幾個接口串行起來,等最后一個接口返回再執行刷新界面的方法,這樣做的話如果其中一個接口返回失敗,那么整個頁面就無法刷新了。還有的同學每個接口回來都刷新一次界面,這樣會造成頁面閃爍,嚴重的話,并發調用同時回來結果操作同一數據源,還有可能造成崩潰。

這時無疑用GCD調度組是最好的解決方法。調度組會在組里所有的任務執行完畢后發送一個通知告訴我們,組內的任務全部執行完畢。

接收通知的方式有兩種,

同步執行的dispatch_block_wait,會阻塞當前線程并等待之前的任務全部執行完或超時再執行wait中隊列里的任務

異步執行的dispatch_group_notify,作用和wait一樣,但是是異步執行的,所以不會阻塞當前線程

dispatch_group_enter和dispatch_group_leave可以手動管理group中的任務計數,enter為+1,leave為-1,當計數為0時,才會進入wait或notify中的任務

具體執行看代碼:這里用after延遲提交任務(block)的做法來模擬調用接口時的情景。


調度組方法執行結果

以上代碼中創建了一個調度組group,并且指定調度組中的任務在全局隊列中運行。在執行結果中可以看到,全局隊列中先執行了任務2和任務1(強制停止了1秒),因為wait會在當前線程等待任務1,2都完成之后才執行,所以wait執行完后再執行任務3,4,這里用了手動計數的方法控制任務計數,當3,4都執行完后,計數歸0,最后計入notify的任務,當我們需要同時并發執行多個接口之后再執行某項操作時,調度組非常實用。

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

GCD的任務和隊列都是在線程中運行的,所以頻繁的操作線程如果不注意會很容易造成死鎖問題,所謂死鎖,就是指兩個線程互相等待對方完成某項操作,導致線程卡死,當然歸根結底是對任務和隊列的運行方式理解的還不夠徹底,下面列舉一些容易造成死鎖的現象,coding中要格外注意。

案例1:最簡單的死鎖現象

控制臺只輸出了1

控制臺:

1.

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

因為同步線程阻塞了主線程,所以任務2等待任務3執行,任務3又等待任務2,造成死鎖,程序卡死。

這時如果我們再稍微復雜一些呢


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


案例2:串行隊列中同步執行一個并行隊列中的任務


同步運行全局隊列中的任務


控制臺:

1

2

3

這個比較好理解,在主線程中打印1,這時同步線程在全局隊列里面執行2,不會像1一樣把任務2直接加在主隊列隊尾,所以不存在2,3相互等待的情況,而是同步線程阻塞了主線程后等待任務2執行完畢后,順序執行3.

案例3:異步線程執行后回到同步線程執行


是不是很眼熟,這就是4.實戰場景中的第一個案例,我們當然不是要演示這個,繼續看下圖兩張圖


控制臺:

1

8

2

3

4

5

6

7

控制臺:

1

8

2

7

3

4

5

6


控制臺:


1,4順序不一定

分析:輸出0后,就是異步線程,所以任務4不用等待,1,4執行順序不一定。任務4完成后,接著是一個阻塞線程的同步任務5,但是加入到全局隊列的異步線程不受影響,繼續執行1后面的同步線程中的任務2,并且任務3需要等任務2完成后才能執行。但是這時主線程已經被一個同步線程的任務5,和6死鎖,所以任務2也無法執行。

總結

GCD除了上面說的這些,只要理解了他的運行方式,可以靈活的組合出很多用法,當然這篇文章只是說了GCD的鳳毛麟角,NSOperation和NSOperationQueue還沒有提到,先理解了GCD,咱們下次說NSOperation和NsOperationQueue。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容