iOS-圖文表并茂擂涛,手把手教你GCD

前言

對(duì)初學(xué)者來(lái)說(shuō),GCD似乎是一道邁不過(guò)去的坎,很多人在同步撒妈、異步恢暖、串行、并行和死鎖這幾個(gè)名詞的漩渦中漸漸放棄治療狰右。本文將使用圖文表并茂的方式給大家形象地解釋其中的原理和規(guī)律杰捂。

線程、任務(wù)和隊(duì)列的概念

異步棋蚌、同步 & 并行嫁佳、串行的特點(diǎn)

一條重要的準(zhǔn)則

一般來(lái)說(shuō),我們使用GCD的最大目的是在新的線程同時(shí)執(zhí)行多個(gè)任務(wù)谷暮,這意味著我們需要兩項(xiàng)條件:

  • 能開(kāi)啟新的線程
  • 任務(wù)可以同時(shí)執(zhí)行
  • 結(jié)合以上兩個(gè)條件蒿往,也就等價(jià)“開(kāi)啟新線程的能力 + 任務(wù)同步執(zhí)行的權(quán)利”,只有在滿足能力與權(quán)利這兩個(gè)條件的前提下湿弦,我們才可以在同時(shí)執(zhí)行多個(gè)任務(wù)瓤漏。

所有組合的特點(diǎn)

(一)異步執(zhí)行 + 并行隊(duì)列

實(shí)現(xiàn)代碼:
//異步執(zhí)行 + 并行隊(duì)列
- (void)asyncConcurrent{
    //創(chuàng)建一個(gè)并行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("標(biāo)識(shí)符", DISPATCH_QUEUE_CONCURRENT);
    
    NSLog(@"---start---");

    //使用異步函數(shù)封裝三個(gè)任務(wù)
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3---%@", [NSThread currentThread]);
    });
    
    NSLog(@"---end---");
}
打印結(jié)果:
  ---start---
  ---end---
  任務(wù)3---<NSThread: 0x600000070f00>{number = 5, name = (null)}
  任務(wù)2---<NSThread: 0x600000070d80>{number = 4, name = (null)}
  任務(wù)1---<NSThread: 0x608000074100>{number = 3, name = (null)}
解釋
  • 異步執(zhí)行意味著
  • 可以開(kāi)啟新的線程
  • 任務(wù)可以先繞過(guò)不執(zhí)行,回頭再來(lái)執(zhí)行
  • 并行隊(duì)列意味著
    • 任務(wù)之間不需要排隊(duì)颊埃,且具有同時(shí)被執(zhí)行的“權(quán)利”
  • 兩者組合后的結(jié)果
    • 開(kāi)了三個(gè)新線程
    • 函數(shù)在執(zhí)行時(shí)蔬充,先打印了start和end,再回頭執(zhí)行這三個(gè)任務(wù)
    • 這三個(gè)任務(wù)是同時(shí)執(zhí)行的班利,沒(méi)有先后饥漫,所以打印結(jié)果是“任務(wù)3-->任務(wù)2-->任務(wù)1”
步驟圖

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

實(shí)現(xiàn)代碼:
//異步執(zhí)行 + 串行隊(duì)列
- (void)asyncSerial{
    //創(chuàng)建一個(gè)串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("標(biāo)識(shí)符", DISPATCH_QUEUE_SERIAL);
    
    NSLog(@"---start---");
    //使用異步函數(shù)封裝三個(gè)任務(wù)
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}
打印結(jié)果:
 ---start---
 ---end---
任務(wù)1---<NSThread: 0x608000078480>{number = 3, name = (null)}
任務(wù)2---<NSThread: 0x608000078480>{number = 3, name = (null)}
任務(wù)3---<NSThread: 0x608000078480>{number = 3, name = (null)}
解釋
  • 異步執(zhí)行意味著
    • 可以開(kāi)啟新的線程
    • 任務(wù)可以先繞過(guò)不執(zhí)行,回頭再來(lái)執(zhí)行
  • 串行隊(duì)列意味著
    • 任務(wù)必須按添加進(jìn)隊(duì)列的順序挨個(gè)執(zhí)行
  • 兩者組合后的結(jié)果
    • 開(kāi)了一個(gè)新的子線程
    • 函數(shù)在執(zhí)行時(shí)罗标,先打印了start和end庸队,再回頭執(zhí)行這三個(gè)任務(wù)
    • 這三個(gè)任務(wù)是按順序執(zhí)行的,所以打印結(jié)果是“任務(wù)1-->任務(wù)2-->任務(wù)3”
步驟圖

(三)同步執(zhí)行 + 并行隊(duì)列

實(shí)現(xiàn)代碼:
//同步執(zhí)行 + 并行隊(duì)列
- (void)syncConcurrent{
    //創(chuàng)建一個(gè)并行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("標(biāo)識(shí)符", DISPATCH_QUEUE_CONCURRENT);
    
    NSLog(@"---start---");
    //使用同步函數(shù)封裝三個(gè)任務(wù)
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}
打印結(jié)果:
  ---start---
  任務(wù)1---<NSThread: 0x608000065400>{number = 1, name = main}
  任務(wù)2---<NSThread: 0x608000065400>{number = 1, name = main}
  任務(wù)3---<NSThread: 0x608000065400>{number = 1, name = main}
  ---end---
解釋
  • 同步執(zhí)行執(zhí)行意味著
    • 不能開(kāi)啟新的線程
    • 任務(wù)創(chuàng)建后必須執(zhí)行完才能往下走
  • 并行隊(duì)列意味著
    • 任務(wù)之間不需要排隊(duì)馒稍,且具有同時(shí)被執(zhí)行的“”
  • 兩者組合后的結(jié)果
    • 所有任務(wù)都只能在主線程中執(zhí)行
    • 函數(shù)在執(zhí)行時(shí)皿哨,必須按照代碼的書(shū)寫(xiě)順序一行一行地執(zhí)行完才能繼續(xù)
  • 注意事項(xiàng)
    • 在這里即便是并行隊(duì)列,任務(wù)可以同時(shí)執(zhí)行纽谒,但是由于只存在一個(gè)主線程证膨,所以沒(méi)法把任務(wù)分發(fā)到不同的線程去同步處理,其結(jié)果就是只能在主線程里按順序挨個(gè)挨個(gè)執(zhí)行了
步驟圖

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

實(shí)現(xiàn)代碼:
- (void)syncSerial{
    //創(chuàng)建一個(gè)串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("標(biāo)識(shí)符", DISPATCH_QUEUE_SERIAL);
    
    NSLog(@"---start---");
    //使用異步函數(shù)封裝三個(gè)任務(wù)
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}
打印結(jié)果:
  ---start---
  任務(wù)1---<NSThread: 0x608000065400>{number = 1, name = main}
  任務(wù)2---<NSThread: 0x608000065400>{number = 1, name = main}
  任務(wù)3---<NSThread: 0x608000065400>{number = 1, name = main}
  ---end---
解釋
  • 這里的執(zhí)行原理和步驟圖跟“同步執(zhí)行+并發(fā)隊(duì)列”是一樣的鼓黔,只要是同步執(zhí)行就沒(méi)法開(kāi)啟新的線程央勒,所以多個(gè)任務(wù)之間也一樣只能按順序來(lái)執(zhí)行,

(五)異步執(zhí)行+主隊(duì)列

實(shí)現(xiàn)代碼:
- (void)asyncMain{
    //獲取主隊(duì)列
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    NSLog(@"---start---");
    //使用異步函數(shù)封裝三個(gè)任務(wù)
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}
打印結(jié)果:
  ---start---
  ---end---
  任務(wù)1---<NSThread: 0x60800006ff40>{number = 1, name = main}
  任務(wù)2---<NSThread: 0x60800006ff40>{number = 1, name = main}
  任務(wù)3---<NSThread: 0x60800006ff40>{number = 1, name = main}
解釋
  • 異步執(zhí)行意味著
    • 可以開(kāi)啟新的線程
    • 任務(wù)可以先繞過(guò)不執(zhí)行澳化,回頭再來(lái)執(zhí)行
  • 主隊(duì)列跟串行隊(duì)列的區(qū)別
    • 隊(duì)列中的任務(wù)一樣要按順序執(zhí)行
    • 主隊(duì)列中的任務(wù)必須在主線程中執(zhí)行崔步,不允許在子線程中執(zhí)行
  • 以上條件組合后得出結(jié)果:
    • 所有任務(wù)都可以先跳過(guò),之后再來(lái)“按順序”執(zhí)行
步驟圖

(六)同步執(zhí)行+主隊(duì)列(死鎖)

實(shí)現(xiàn)代碼:
- (void)syncMain{
    //獲取主隊(duì)列
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    NSLog(@"---start---");
    //使用同步函數(shù)封裝三個(gè)任務(wù)
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}
打印結(jié)果:
  ---start---
解釋
  • 主隊(duì)列中的任務(wù)必須按順序挨個(gè)執(zhí)行
  • 任務(wù)1要等主線程有空的時(shí)候(即主隊(duì)列中的所有任務(wù)執(zhí)行完)才能執(zhí)行
  • 主線程要執(zhí)行完“打印end”的任務(wù)后才有空
  • “任務(wù)1”和“打印end”兩個(gè)任務(wù)互相等待缎谷,造成死鎖
步驟圖

寫(xiě)在結(jié)尾的話

以上就是我對(duì)GCD的基礎(chǔ)知識(shí)和幾種組合的理解井濒,如果覺(jué)得我的博客寫(xiě)得還可以,歡迎關(guān)注我的博客,本人將長(zhǎng)期為大家推出高質(zhì)量的技術(shù)博客瑞你。當(dāng)然酪惭,如果覺(jué)得我哪里理解有錯(cuò)的,也可以留下你的評(píng)論者甲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末春感,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子虏缸,更是在濱河造成了極大的恐慌鲫懒,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刽辙,死亡現(xiàn)場(chǎng)離奇詭異窥岩,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)扫倡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)谦秧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人撵溃,你說(shuō)我怎么就攤上這事∽独郏” “怎么了缘挑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)桶略。 經(jīng)常有香客問(wèn)我语淘,道長(zhǎng),這世上最難降的妖魔是什么际歼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任惶翻,我火速辦了婚禮,結(jié)果婚禮上鹅心,老公的妹妹穿的比我還像新娘吕粗。我一直安慰自己,他們只是感情好旭愧,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布颅筋。 她就那樣靜靜地躺著,像睡著了一般输枯。 火紅的嫁衣襯著肌膚如雪议泵。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天桃熄,我揣著相機(jī)與錄音先口,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛碉京,可吹牛的內(nèi)容都是我干的桩引。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼收夸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坑匠!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起卧惜,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤厘灼,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后咽瓷,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體设凹,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年茅姜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了闪朱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钻洒,死狀恐怖奋姿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情素标,我是刑警寧澤称诗,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站头遭,受9級(jí)特大地震影響寓免,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜计维,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一袜香、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鲫惶,春花似錦蜈首、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至艺蝴,卻和暖如春猬腰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猜敢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工姑荷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盒延,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓鼠冕,卻偏偏與公主長(zhǎng)得像添寺,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懈费,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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

  • 從哪說(shuō)起呢计露? 單純講多線程編程真的不知道從哪下嘴。憎乙。 不如我直接引用一個(gè)最簡(jiǎn)單的問(wèn)題票罐,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,774評(píng)論 1 17
  • 轉(zhuǎn)載自:http://www.cocoachina.com/ios/20161031/17887.html 前言對(duì)...
    YYT1992閱讀 443評(píng)論 0 2
  • 目錄(GCD): 關(guān)鍵詞 混淆點(diǎn) 場(chǎng)景應(yīng)用 總結(jié) 1. 關(guān)鍵詞 線程概念: 獨(dú)立執(zhí)行的代碼段该押,一個(gè)線程同時(shí)間只能執(zhí)...
    Ryan___閱讀 1,273評(píng)論 0 3
  • .一.進(jìn)程 進(jìn)程:是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空...
    IIronMan閱讀 4,494評(píng)論 1 33
  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了阵谚!去的時(shí)候我都想好了最壞的可能(胃癌)蚕礼,之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,245評(píng)論 21 42