iOS - 多線程(二) GCD講解

目錄:

1.GCD簡(jiǎn)介

2.串行隊(duì)列 + 同步執(zhí)行

3.串行隊(duì)列 + 異步執(zhí)行

4.并發(fā)隊(duì)列 + 同步執(zhí)行

5.并發(fā)隊(duì)列 + 異步執(zhí)行

6.全局隊(duì)列

7.主隊(duì)列

8.線程間通信

9.GCD柵欄函數(shù)(dispatch_barrier_async)

10.GCD調(diào)度組

一.GCD簡(jiǎn)介

注意:開啟線程的操作是CPU做的讥此,GCD只負(fù)責(zé)任務(wù)的調(diào)度倒慧。


(1).GCD中涉及到兩個(gè)十分重要的概念, 就是任務(wù)隊(duì)列.

任務(wù)(Task): 你需要執(zhí)行的操作;

隊(duì)列(Queue): 存放任務(wù)的容器艺糜。


(2).GCD使用步驟一姿,2步。

????? 定制任務(wù)(確定想要做的事情);

??? ? 然后將任務(wù)添加到隊(duì)列中( GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出來见芹,放到對(duì)應(yīng)的線程中執(zhí)行。取任務(wù)遵循隊(duì)列FIFO原則:先添加進(jìn)隊(duì)列的任務(wù)先被取出來)蠢涝。


(3).GCD中的隊(duì)列分2類

?????? 并發(fā)隊(duì)列:可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(能夠開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))玄呛,并發(fā)功能只有在異步執(zhí)行函數(shù)下有效。

?????? 串行隊(duì)列:任務(wù)只能在同一條線程中(可以是主線程和二,也可以是子線程)一個(gè)一個(gè)按順序執(zhí)行徘铝。


(4).任務(wù)執(zhí)行分為同步執(zhí)行和異步執(zhí)行

? ? ? ? 同步執(zhí)行 :dispatch_sync(dispatch_queue_t? _Nonnull queue, ^(void)block),一個(gè)任務(wù)沒有結(jié)束,就不會(huì)去執(zhí)行下一個(gè)任務(wù)惕它。同步執(zhí)行函數(shù)無法開啟新線程怕午。

? ? ??? 異步執(zhí)行: dispatch_async(dispatch_queue_t? _Nonnull queue, ^(void)block),不用等待任務(wù)執(zhí)行完淹魄,就可以執(zhí)行下一個(gè)任務(wù)郁惜。異步執(zhí)行函數(shù)有能力開啟新線程。


二.各種情況詳細(xì)分析

?

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

? ?????? //1.隊(duì)列 -- 串行 DISPATCH_QUEUE_SERIAL 串行 等價(jià)于NULL

???????? dispatch_queue_t q = dispatch_queue_create("CC_GCD", NULL);

??????? //2.先循環(huán)添加任務(wù)揭北,同步執(zhí)行任務(wù)

???????? for (int i = 0;? i < 10; i++) {

??????????????? dispatch_sync(q, ^{

????????????????????????? NSLog(@"%@扳炬,%d",[NSThread currentThread],i);

?????????? });

??? 分析:首先創(chuàng)建了一個(gè)串行隊(duì)列,然后循環(huán)向隊(duì)列中添加10個(gè)任務(wù)搔体,調(diào)用GCD同步執(zhí)行函數(shù)執(zhí)行隊(duì)列中的任務(wù)恨樟。 由于是同步執(zhí)行所以不會(huì)開啟新的線程,任務(wù)都添加在串行隊(duì)列疚俱,所以這些打印會(huì)按順序執(zhí)行劝术,且都在主線程中執(zhí)行。


??? (2).串行隊(duì)列 + 異步執(zhí)行

??????????? //1.隊(duì)列 -- 串行 DISPATCH_QUEUE_SERIAL 串行 等價(jià)于NULL

??????????? dispatch_queue_t q = dispatch_queue_create("CC_GCD", NULL);

? ? ? ? ? //2..先循環(huán)添加任務(wù)呆奕,異步執(zhí)行任務(wù)

?????????? for (int i = 0;? i < 10; i++) {

???????????????? NSLog(@"%d------------- ",i);

???????????????? dispatch_async(q, ^{

???????????? ? ?? NSLog(@"%@养晋,%d",[NSThread currentThread],i);

???????????????? });

?????? ? ? }

????????? NSLog(@"come here");

分析:首先創(chuàng)建了一個(gè)串行隊(duì)列,然后循環(huán)向隊(duì)列中添加10個(gè)任務(wù)梁钾,調(diào)用GCD異步執(zhí)行函數(shù)執(zhí)行隊(duì)列中的任務(wù)绳泉。 由于是異步執(zhí)行所以會(huì)開啟新的線程,任務(wù)都添加在串行隊(duì)列姆泻,所以這些打印會(huì)按順序執(zhí)行零酪,但是是在新的線程中執(zhí)行,子線程只會(huì)開啟1條拇勃。



??? (3).并發(fā)隊(duì)列 + 同步執(zhí)行

?????????????? //1.隊(duì)列 DISPATCH_QUEUE_CONCURRENT

????????????? dispatch_queue_t q = dispatch_queue_create("CC_GCD", DISPATCH_QUEUE_CONCURRENT);

???????????? //2.同步執(zhí)行任務(wù)

???????????? for (int i = 0;? i < 10; i++) {

????????? ? ? ? ? ? NSLog(@"%d------------- ",i);

?????????? ? ? ? ?? dispatch_sync(q, ^{

?????????????????????? ? ? ? NSLog(@"%@四苇,%d",[NSThread currentThread],i);

??????????????????? });

????????????? }

????????????? NSLog(@"come here");

分析:首先創(chuàng)建了一個(gè)并發(fā)隊(duì)列,然后循環(huán)向隊(duì)列中添加10個(gè)任務(wù)方咆,調(diào)用GCD同步執(zhí)行函數(shù)執(zhí)行隊(duì)列中的任務(wù)月腋。 由于是同步執(zhí)行所以不會(huì)開啟新的線程,任務(wù)都添加在并發(fā)隊(duì)列瓣赂,雖然我們說并發(fā)隊(duì)列里面的任務(wù)可以同時(shí)取出來執(zhí)行榆骚,但是這里是同步執(zhí)行,沒有開啟新的線程煌集,所以這些打印還是會(huì)按順序執(zhí)行寨躁,且都在主線程中執(zhí)行。



??? (4).并發(fā)隊(duì)列 + 異步執(zhí)行

??????????????? //1.隊(duì)列 DISPATCH_QUEUE_CONCURRENT

??????????????? dispatch_queue_t q = dispatch_queue_create("CC_GCD", DISPATCH_QUEUE_CONCURRENT);

?????????????? //2.異步執(zhí)行任務(wù)

?????????????? for (int i = 0;? i < 10; i++) {

?????????????????????? NSLog(@"%d------------- ",i);

????????????????????? dispatch_async(q, ^{

?????????????????????????????? NSLog(@"%@牙勘,%d",[NSThread currentThread],i);

????????????? ? ? ? ? });

???????????? ?? }

??????????????? NSLog(@"come here");

分析:首先創(chuàng)建了一個(gè)并發(fā)隊(duì)列,然后循環(huán)向隊(duì)列中添加10個(gè)任務(wù),調(diào)用GCD異步執(zhí)行函數(shù)執(zhí)行隊(duì)列中的任務(wù)方面。 由于是異步執(zhí)行所以會(huì)開啟新的線程放钦,任務(wù)都添加在并發(fā)隊(duì)列,所以這十個(gè)任務(wù)能夠同時(shí)執(zhí)行恭金,那么久會(huì)開啟多條線程操禀,至于開啟幾條線程用CPU決定,程序員無法決定横腿。



? (5).全局隊(duì)列(本質(zhì)上是一個(gè)并發(fā)隊(duì)列)

?????? 創(chuàng)建全局隊(duì)列函數(shù):dispatch_get_global_queue(long identifier, unsigned long flags);

? ? ? 參數(shù)說明:? ? 參數(shù)一:涉及系統(tǒng)適配

?????????????????????????????????????? iOS 8.0 服務(wù)質(zhì)量

?????????????????????????????????????? QOS_CLASS_USER_INTERACTIVE? 用戶交互(希望線程快速執(zhí)行颓屑,不要放一些耗時(shí)操作)

?????????????????????????????????????? QOS_CLASS_USER_INITIATED? ? 用戶需要的(不要放一些耗時(shí)操作)

?????????????????????????????????????? QOS_CLASS_DEFAULT? ? ? ? ? 0 默認(rèn)

?????????????????????????????????????? QOS_CLASS_UTILITY? ? ? ? ? 使用工具(用來耗時(shí)操作)

?????????????????????????????????????? QOS_CLASS_BACKGROUND? ? ? ? 后臺(tái)

?????????????????????????????????????? QOS_CLASS_UNSPECIFIED? ? ? 沒有指定優(yōu)先級(jí)

?????????????????????????????????????? iOS 7.0 調(diào)度優(yōu)先級(jí)

?????????????????????????????????????? DISPATCH_QUEUE_PRIORITY_HIGH? ? ? 高優(yōu)先級(jí)

?????????????????????????????????????? DISPATCH_QUEUE_PRIORITY_DEFAULT 0 默認(rèn)優(yōu)先級(jí)

?????????????????????????????????????? DISPATCH_QUEUE_PRIORITY_LOW (-2)? 低優(yōu)先級(jí)

?????????????????????????????????????? DISPATCH_QUEUE_PRIORITY_BACKGROUND 后臺(tái)優(yōu)先級(jí)

? ? ? ? ? ? ? ? ? ? ? ? ? 參數(shù)二:為未來的保留參數(shù),

?????????????????????????????????????? 提示:尤其不要選擇BACKGROUND? 耿焊,線程執(zhí)行會(huì)慢到令人發(fā)指揪惦!



(6).主隊(duì)列(本質(zhì)上是一個(gè)并發(fā)隊(duì)列)

??????? 創(chuàng)建主隊(duì)列函數(shù):dispatch_get_main_queue(void)

??????? 注:主隊(duì)列上的任務(wù)只能夠在主線程上執(zhí)行,所以無論同步執(zhí)行還是異步執(zhí)行函數(shù)罗侯,都不會(huì)開啟新線程器腋。

??????? 主隊(duì)列+同步執(zhí)行

?????? NSLog(@"------start-------");

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

?????????????????? NSLog(@"download1-------%@",[NSThread currentThread]);

?????? });

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

?????????????????? NSLog(@"download1-------%@",[NSThread currentThread]);

???????? });

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

????????? ? ? ? ?? NSLog(@"download1-------%@",[NSThread currentThread]);

?????? });

????? NSLog(@"-------end---------");

分析:現(xiàn)在是直接崩潰了, 以前這種情況是會(huì)發(fā)生死鎖的。

????

? ? ? ?? 主隊(duì)列+異步函數(shù)

???????? // 1.獲得主隊(duì)列

??????? dispatch_queue_t queue = dispatch_get_main_queue();

??????? NSLog(@"-----start------");

????? // 2.將任務(wù)封裝到異步函數(shù)中 钩杰,添加任務(wù)到主隊(duì)列中

????? dispatch_async(queue, ^{

?????????????? NSLog(@"download1 ----- %@", [NSThread currentThread]);

?????? });

?????? dispatch_async(queue, ^{

????????????? NSLog(@"download2 ----- %@", [NSThread currentThread]);

????? });

????? dispatch_async(queue, ^{

????? NSLog(@"download3 ----- %@", [NSThread currentThread]);

????? });

???? NSLog(@"-----end------");

分析:不開線程纫塌,start和end執(zhí)行完后,主隊(duì)列中的任務(wù)串行在主線程執(zhí)行讲弄。



(7).? 線程間通信


???? // 1. 創(chuàng)建子線程處理耗時(shí)操作

??? dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

?? ? ? ? ? ? ? ? ? //1.1耗時(shí)操作開始

? ? ? ? ? ? ? ? ? for (int i = 0; i < 10000; i++) {

????? ? ? ? ? ? ? ? ? ? NSLog(@"---耗時(shí)操作-%@----%d", [NSThread currentThread],i);

? ? ? ? ? ? ? ?? }

? ? ? ? ? ? ?? //1.2耗時(shí)操作完成回到主線程中

? ? ? ? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{

??????? ? ? ? ? ? ? ? ? NSLog(@"----%@----", [NSThread currentThread]);

? ? ? ? ? ?? });

});



(8)GCD柵欄函數(shù)(dispatch_barrier_async)

?????????? dispatch_barrier_async函數(shù)的作用與barrier的意思相同,在進(jìn)程管理中起到一個(gè)柵欄的作用,它等待所有位于barrier函數(shù)之前的操作執(zhí)行完畢后執(zhí)行,并且在barrier函數(shù)執(zhí)行之后,barrier函數(shù)之后的操作才會(huì)得到執(zhí)行,該函數(shù)需要同dispatch_queue_create函數(shù)生成的concurrent Dispatch Queue隊(duì)列一起使用措左。

例:

柵欄函數(shù)使用示例代碼

輸出結(jié)果:

分析:前十個(gè) --> barrier -->后十個(gè)? 其中 前十個(gè) 與 后十個(gè) 由于并行處理先后順序不定

運(yùn)用場(chǎng)景:用barrier實(shí)現(xiàn): 讀-寫鎖,讀-寫鎖有以下幾個(gè)特點(diǎn):? 在沒有寫操作的時(shí)候, 可以任意的并發(fā)讀取, 在所有讀操作完成后, 才進(jìn)行寫操作, 但是寫操作不可以并發(fā), 且在寫操作過程中, 不能讀取, 在寫操作完成后, 又可以任意的并發(fā)讀取了避除。如果我們使用barrier GCD接口來處理寫操作, 使用普通的GCD接口來并發(fā)讀取, 那么完全滿足讀-寫鎖的以上特點(diǎn)

dispatch_barrier_sync和dispatch_barrier_async的區(qū)別:

在將任務(wù)插入到queue的時(shí)候怎披,dispatch_barrier_sync需要等待自己的任務(wù)結(jié)束之后才會(huì)繼續(xù)程序,然后插入被寫在它后面的任務(wù)驹饺,然后執(zhí)行后面的任務(wù)

而dispatch_barrier_async將自己的任務(wù)插入到queue之后钳枕,不會(huì)等待自己的任務(wù)結(jié)束,它會(huì)繼續(xù)把后面的任務(wù)插入到queue

所以赏壹,dispatch_barrier_async的不等待(異步)特性體現(xiàn)在將任務(wù)插入隊(duì)列的過程鱼炒,它的等待特性體現(xiàn)在任務(wù)真正執(zhí)行的過程。


(9).GCD調(diào)度組

使用場(chǎng)景:在實(shí)際開發(fā)中蝌借,需要開啟N個(gè)異步線程昔瞧,但是后續(xù)操作,需要依賴N個(gè)線程返回的數(shù)據(jù)菩佑,需要接收所有線程任務(wù)執(zhí)行完成的通知自晰。

例:

#pragma mark - 調(diào)度組

- (void)group{

/*

*應(yīng)用場(chǎng)景:

開發(fā)的時(shí)候,有時(shí)候出現(xiàn)多個(gè)網(wǎng)絡(luò)請(qǐng)求都完成以后(每個(gè)網(wǎng)絡(luò)請(qǐng)求時(shí)間的時(shí)長(zhǎng)不一樣)稍坯,再通知用戶

比如下載書:三國(guó)演義酬荞,紅樓夢(mèng)搓劫,西游記

*/

????????? //1.實(shí)例化一個(gè)調(diào)度組

??????? dispatch_group_t group = dispatch_group_create();

?????? //2.隊(duì)列

?????? dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

????? //3.任務(wù)添加到隊(duì)列queue

???? dispatch_group_async(group,? queue, ^{

????? ?? ? for (int i = 0; i<=50; i++) {

????????????????? if (i == 50) {

????????????????????? NSLog(@"---下載小說A:%@",[NSThread currentThread]);

????????????????? }

????????? }

?? });

? dispatch_group_async(group,? queue, ^{

???????? for (int i = 0; i<=50; i++) {

??????????????? if (i == 50) {

??????????????????? NSLog(@"---下載小說B:%@",[NSThread currentThread]);

????????????? }

??? }

});

dispatch_group_async(group,? queue, ^{

???????? for (int i = 0; i<=500; i++) {

?????????????? if (i == 50) {

??????????????????? NSLog(@"---下載小說C:%@",[NSThread currentThread]);

???????????? }

??????? }

});

//4.獲得所有調(diào)度組里面的異步任務(wù)完成的通知<上面3本書都下載完了才會(huì)執(zhí)行>

??? dispatch_group_notify(group, queue, ^{

?????????? NSLog(@"--- 下載完成的操作:%@",[NSThread currentThread]);

? });

}

輸出結(jié)果:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市混巧,隨后出現(xiàn)的幾起案子枪向,更是在濱河造成了極大的恐慌,老刑警劉巖咧党,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秘蛔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡傍衡,警方通過查閱死者的電腦和手機(jī)深员,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛙埂,“玉大人倦畅,你說我怎么就攤上這事∠洳校” “怎么了滔迈?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)被辑。 經(jīng)常有香客問我燎悍,道長(zhǎng),這世上最難降的妖魔是什么盼理? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任谈山,我火速辦了婚禮,結(jié)果婚禮上宏怔,老公的妹妹穿的比我還像新娘奏路。我一直安慰自己,他們只是感情好臊诊,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布鸽粉。 她就那樣靜靜地躺著,像睡著了一般抓艳。 火紅的嫁衣襯著肌膚如雪触机。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天玷或,我揣著相機(jī)與錄音儡首,去河邊找鬼。 笑死偏友,一個(gè)胖子當(dāng)著我的面吹牛蔬胯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播位他,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼氛濒,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼产场!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起泼橘,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤涝动,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后炬灭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡靡菇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年重归,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厦凤。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鼻吮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出较鼓,到底是詐尸還是另有隱情椎木,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布博烂,位于F島的核電站香椎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏禽篱。R本人自食惡果不足惜畜伐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望躺率。 院中可真熱鬧玛界,春花似錦、人聲如沸悼吱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽后添。三九已至笨枯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吕朵,已是汗流浹背猎醇。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留努溃,地道東北人硫嘶。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像梧税,于是被迫代替她去往敵國(guó)和親沦疾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子称近,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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