關(guān)于iOS 多線程開發(fā)——GCD的理解與使用


GCD是Grand Central Dispatch的縮寫您市,有人叫它大中樞派發(fā)观挎、或者大中央調(diào)度琴儿,不管叫啥,總之嘁捷,它是iOS開發(fā)的一個多線程編程解決方法造成,比起NSThread、NSOperationQueue雄嚣、NSInvocationOperation等多線程技術(shù)方案晒屎,使用起來更加簡單方便。

GCD的優(yōu)點(diǎn):1.GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案

? ? ? ? ? ? ? ? ? ?2.GCD會自動利用更多的CPU內(nèi)核(比如雙核现诀、四核)

? ? ? ? ? ? ? ? ? ?3.GCD會自動管理線程的生命周期(創(chuàng)建線程夷磕、調(diào)度任務(wù)履肃、銷毀線程)

? ? ? ? ? ? ? ? ? 4.程序員只需要告訴GCD想要執(zhí)行什么任務(wù)仔沿,不需要編寫任何線程管理代碼

一、基本概念理解

1尺棋、進(jìn)程和線程的理解

1. 進(jìn)程:正在進(jìn)行中的程序被稱為進(jìn)程封锉,負(fù)責(zé)程序運(yùn)行的內(nèi)存分配,每一個進(jìn)程都有自己獨(dú)立的虛擬內(nèi)存空間膘螟。

2. 線程是進(jìn)程中一個獨(dú)立的執(zhí)行路徑成福,即主線程,主線程有1M的棧區(qū)荆残,對于耗時的執(zhí)行路徑奴艾,可以放在子線程(512K棧區(qū))中執(zhí)行。

注意:(1)新建線程會消耗內(nèi)存空間和CPU事件内斯,線程太多會降低系統(tǒng)的運(yùn)行性能蕴潦,多線程是通過CPU時分復(fù)用實(shí)現(xiàn)的像啼。

? ? ? ? ?(2)多線程是為了并發(fā)執(zhí)行多項(xiàng)任務(wù),不會提高單個算法本身的執(zhí)行效率潭苞。

2忽冻、并發(fā)(Concurrency),并行(Parallelism)的理解

舉個形象的例子:A此疹、B兩個基佬某天相約去小樹林-------挖坑僧诚,

1. A和B各要挖一個坑,他們只有一把鐵锨蝗碎,于是兩人商量湖笨,A挖一下,把鐵锨給B蹦骑,B挖一下赶么,再把鐵锨給A,這樣交替使用鐵锨脊串,最后兩人各挖了一個大坑辫呻,卻總共花了20分鐘。這就是并發(fā)琼锋;

2. A和B各要挖一個坑放闺,他們各有一把鐵锨,同時挖坑缕坎,最后怖侦,每個人各花了大概10分鐘時間挖完了大坑。這就是并行谜叹。

由此可見匾寝,并發(fā)與并行的區(qū)別:并行是嚴(yán)格意義上的同時執(zhí)行,而并發(fā)并不是嚴(yán)格的同時執(zhí)行荷腊,而是以時間片為單位交替執(zhí)行艳悔,所以不需要多處理器。

3女仰、同步(sync)猜年、異步(async)的理解

舉個形象的例子:A、B是一對情侶疾忍,某天某時A男為B女做好了飯乔外,于是喊B女去吃飯

1. B女在看韓劇,A一直喊她去吃飯一罩,可是B一直不去杨幼,沒辦法,A只能等到B女看完韓劇才能一起吃飯,真愛需要等待差购,真愛就是同步

2. B女在看韓劇补疑,A喊了一聲后,沒管來不來歹撒,自己就去吃飯了莲组,這就是異步

區(qū)別:等待與不等待

4、GCD中串行隊(duì)列(Serial Dispatch Queue) 暖夭、并發(fā)隊(duì)列(Concurrent Dispatch Queue)的理解

GCD使用了隊(duì)列的概念锹杈,解決了NSThread難于管理的問題,可以把隊(duì)列想象成數(shù)組迈着,通常我們把要執(zhí)行的任務(wù)放到隊(duì)列中管理

不管是串行隊(duì)列(SerialQueue)還是并發(fā)隊(duì)列(ConcurrencyQueue)竭望,都是FIFO隊(duì)列。也就意味著裕菠,任務(wù)一定是一個一個地咬清,按照先進(jìn)先出的順序來執(zhí)行。

1.串行隊(duì)列:在創(chuàng)建隊(duì)列時奴潘,傳參數(shù)DISPATCH_QUEUE_SERIAL表示創(chuàng)建串行隊(duì)列旧烧。任務(wù)會一個一個地執(zhí)行,只有前一個任務(wù)執(zhí)行完成画髓,才會繼續(xù)執(zhí)行下一個任務(wù)掘剪。 串行執(zhí)行并不是同步執(zhí)行的意思,一定要注意區(qū)分

2.并發(fā)隊(duì)列:在創(chuàng)建隊(duì)列時奈虾,傳參數(shù)DISPATCH_QUEUE_CONCURRENT表示創(chuàng)建并發(fā)隊(duì)列夺谁。并發(fā)隊(duì)列會盡可能多地創(chuàng)建線程去執(zhí)行任務(wù)。并發(fā)隊(duì)列中的任務(wù)會按入隊(duì)的順序執(zhí)行任務(wù)肉微,但是哪個任務(wù)先完成是不確定的匾鸥。

Serial Dispatch Queue -- 線程池只提供一個線程用來執(zhí)行任務(wù),所以后一個任務(wù)必須等到前一個任務(wù)執(zhí)行結(jié)束才能開始碉纳。

Concurrent Dispatch Queue -- 線程池提供多個線程來執(zhí)行任務(wù)勿负,所以可以按序啟動多個任務(wù)并發(fā)執(zhí)行。

二村象、GCD的使用

創(chuàng)建隊(duì)列的方法

dispatch_queue_t q = dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)

參數(shù):

const char *label:隊(duì)列的名稱

dispatch_queue_attr_t attr:隊(duì)列的屬性笆环,屬性有兩個攒至,分別為:

DISPATCH_QUEUE_SERIAL(NULL)? 串行隊(duì)列

DISPATCH_QUEUE_CONCURRENT? ? 并發(fā)隊(duì)列

隊(duì)列屬性為宏厚者,其中串行隊(duì)列的宏值為NULL,所以創(chuàng)建一個串行隊(duì)列可以用如下代碼

dispatch_queue_t q = dispatch_queue_create(“jianshu", NULL);

同步和異步代表會不會開辟新的線程迫吐。串行和并發(fā)代表任務(wù)執(zhí)行的方式库菲。

同步串行和同步并發(fā),任務(wù)執(zhí)行的方式是一樣的志膀。沒有區(qū)別熙宇,因?yàn)闆]有開辟新的線程鳖擒,所有的任務(wù)都是在一條線程里面執(zhí)行。

異步串行和異步并發(fā)烫止,任務(wù)執(zhí)行的方式是有區(qū)別的蒋荚,異步串行會開辟一條新的線程,隊(duì)列中所有任務(wù)按照添加的順序一個一個執(zhí)行馆蠕,異步并發(fā)會開辟多條線程期升,至于具體開辟多少條線程,是由系統(tǒng)決定的互躬,但是所有的任務(wù)好像就是同時執(zhí)行的一樣播赁。

1.串行隊(duì)列異步任務(wù)

因?yàn)槭钱惒剑海?)會創(chuàng)建新的線程(2)主線程執(zhí)行時間不確定?

因?yàn)槭谴嘘?duì)列:隊(duì)列中所有任務(wù)按照添加的順序一個一個執(zhí)行

異步串行只會開辟一條新的線程去執(zhí)行

2.并發(fā)隊(duì)列異步任務(wù)

并行隊(duì)列下地異步函數(shù)會開啟N條子線程,且執(zhí)行任務(wù)的順序我們無法控制吼渡,至于是哪條線程執(zhí)行任務(wù)由隊(duì)列決定容为,哪個任務(wù)先完成由CPU決定。

結(jié)果中子線程4寺酪,5執(zhí)行了多次任務(wù)坎背,那是因?yàn)檫@兩條線程執(zhí)行完任務(wù)就會被線程池回收,隊(duì)列再從線程池中去線程執(zhí)行任務(wù)寄雀,這時就會線程重復(fù)利用沼瘫,如果沒有線程則會重新創(chuàng)建。

3.串行隊(duì)列同步任務(wù)

同步任務(wù)不會開辟新線程咙俩,所以所有的的任務(wù)都會在主線程上依次執(zhí)行


4.并發(fā)隊(duì)列同步任務(wù)

同步任務(wù)不會開辟新線程耿戚,所以所有的的任務(wù)都會在主線程上依次執(zhí)行

5.主隊(duì)列

在應(yīng)用啟動的時候,就會自動創(chuàng)建與主線程關(guān)聯(lián)的串行隊(duì)列阿趁,我們也可能獲取膜蛔,不能手動創(chuàng)建。主隊(duì)列專門負(fù)責(zé)調(diào)度主線程度的任務(wù)脖阵,沒有辦法開辟新的線程皂股。所以,在主隊(duì)列下的任務(wù)不管是異步任務(wù)還是同步任務(wù)都不會開辟線程命黔,任務(wù)只會在主線程順序執(zhí)行呜呐。

(1)主隊(duì)列異步任務(wù):現(xiàn)將任務(wù)放在主隊(duì)列中,但是不是馬上執(zhí)行悍募,等到主隊(duì)列中的其它所有任務(wù)除我們使用代碼添加到主隊(duì)列的任務(wù)的任務(wù)都執(zhí)行完畢之后才會執(zhí)行我們使用代碼添加的任務(wù)蘑辑。

(2)主隊(duì)列同步任務(wù):容易阻塞主線程,所以不要這樣寫坠宴。原因:我們自己代碼任務(wù)需要馬上執(zhí)行洋魂,但是主線程正在執(zhí)行代碼任務(wù)的方法體,因此代碼任務(wù)就必須等待,而主線程又在等待代碼任務(wù)的完成好去完成下面的任務(wù)副砍,因此就形成了相互等待衔肢。整個主線程就被阻塞了。

提示:注意主線程是一直工作的豁翎,除非將程序殺掉角骤,否則主線程的工作永遠(yuǎn)不會結(jié)束。

6.全局隊(duì)列

是一種特殊的并行隊(duì)列心剥,獲取全局隊(duì)列的方法:dispatch_get_global_queue(long identifier启搂,unsigned long flags)

參數(shù)1:代表該任務(wù)的優(yōu)先級,默認(rèn)寫0就行刘陶,不要使用系統(tǒng)提供的枚舉類型(見過好多人都使用DISPATCH_QUEUE_PRIORITY_DEFAULT)胳赌,因?yàn)閕os7和ios8的枚舉數(shù)值不一樣,使用數(shù)字可以通用匙隔。

#define DISPATCH_QUEUE_PRIORITY_HIGH 2

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

#define DISPATCH_QUEUE_PRIORITY_LOW (-2)

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

參數(shù)2:蘋果保留關(guān)鍵字疑苫,一般也寫0

全局隊(duì)列和并發(fā)隊(duì)列的區(qū)別:

(1)全局隊(duì)列沒有名字,但是并發(fā)隊(duì)列有名字纷责。有名字可以便于查看系統(tǒng)日志

(2)全局隊(duì)列是所有應(yīng)用程序共享的捍掺。

(3)在mrc的時候,全局隊(duì)列不用手動釋放再膳,但是并發(fā)隊(duì)列需要挺勿。

全局隊(duì)列的使用:通常,我們可以在global_queue中做一些long-running的任務(wù)喂柒,完成后在main_queue中更新UI不瓶,避免UI阻塞,無法響應(yīng)用戶操作:

7.dispatch_group_async的使用

dispatch_group_async可以實(shí)現(xiàn)監(jiān)聽一組任務(wù)是否完成灾杰,完成后得到通知執(zhí)行其他的操作蚊丐。這個方法很有用,比如執(zhí)行四個下載任務(wù)艳吠,當(dāng)四個任務(wù)都下載完成后才通知界面說完成麦备。

關(guān)于dispatch_group_async其他使用的方式此處暫不考慮

8.dispatch_barrier_async的使用

dispatch_barrier_async是在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,而且它后面的任務(wù)等它執(zhí)行完成之后才會執(zhí)行

如果使用dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);會發(fā)現(xiàn)運(yùn)行結(jié)果為:

說明dispatch_barrier_async的順序執(zhí)行還是依賴queue的類型啊昭娩,必需要queue的類型為dispatch_queue_create創(chuàng)建的凛篙,而且attr參數(shù)值必需是DISPATCH_QUEUE_CONCURRENT類型,前面兩個非dispatch_barrier_async的類型的執(zhí)行是依賴其本身的執(zhí)行時間的栏渺,如果attr如果是DISPATCH_QUEUE_SERIAL時呛梆,那就完全是符合Serial queue的FIFO特征了。



9.dispatch_once

dispatch_once這個函數(shù)迈嘹,它可以保證整個應(yīng)用程序生命周期中某段代碼只被執(zhí)行一次削彬!

10.dispatch_after

有時候需要等幾秒鐘后處理一些事情


注:動手練練有助于理解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末全庸,一起剝皮案震驚了整個濱河市秀仲,隨后出現(xiàn)的幾起案子融痛,更是在濱河造成了極大的恐慌,老刑警劉巖神僵,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雁刷,死亡現(xiàn)場離奇詭異,居然都是意外死亡保礼,警方通過查閱死者的電腦和手機(jī)沛励,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炮障,“玉大人目派,你說我怎么就攤上這事⌒灿” “怎么了企蹭?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長智末。 經(jīng)常有香客問我谅摄,道長,這世上最難降的妖魔是什么系馆? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任送漠,我火速辦了婚禮,結(jié)果婚禮上由蘑,老公的妹妹穿的比我還像新娘闽寡。我一直安慰自己,他們只是感情好尼酿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布下隧。 她就那樣靜靜地躺著,像睡著了一般谓媒。 火紅的嫁衣襯著肌膚如雪淆院。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天句惯,我揣著相機(jī)與錄音土辩,去河邊找鬼。 笑死抢野,一個胖子當(dāng)著我的面吹牛拷淘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播指孤,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼启涯,長吁一口氣:“原來是場噩夢啊……” “哼贬堵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起结洼,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤黎做,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后松忍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒸殿,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年鸣峭,在試婚紗的時候發(fā)現(xiàn)自己被綠了宏所。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡摊溶,死狀恐怖爬骤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情莫换,我是刑警寧澤霞玄,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站浓镜,受9級特大地震影響溃列,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜膛薛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一听隐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哄啄,春花似錦雅任、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至锌半,卻和暖如春禽车,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刊殉。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工殉摔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人记焊。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓逸月,卻偏偏與公主長得像,于是被迫代替她去往敵國和親遍膜。 傳聞我的和親對象是個殘疾皇子碗硬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

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