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決定。
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_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
有時候需要等幾秒鐘后處理一些事情
注:動手練練有助于理解