多線程編程之GCD

GCD是什么:一句話負(fù)責(zé)線程池的中央調(diào)度

GCD全稱為Grand Central Dispatch顶滩,是libdispatch的市場(chǎng)名稱,而libdispatch是Apple的一個(gè)庫(kù),其為并發(fā)代碼在iOS和OS X的多核硬件上執(zhí)行提供支持。確切地說(shuō)GCD是一套低層級(jí)的C API,通過(guò) GCD屯伞,開(kāi)發(fā)者只需要向隊(duì)列中添加一段代碼塊(block或C函數(shù)指針),而不需要直接和線程打交道蝌数。GCD在后端管理著一個(gè)線程池愕掏,它不僅決定著你的代碼塊將在哪個(gè)線程被執(zhí)行,還根據(jù)可用的系統(tǒng)資源對(duì)這些線程進(jìn)行管理顶伞。這樣通過(guò)GCD來(lái)管理線程饵撑,從而解決線程被創(chuàng)建的問(wèn)題。

GCD的優(yōu)勢(shì)

  • 易用: GCD 提供一個(gè)易于使用的并發(fā)模型而不僅僅只是鎖和線程唆貌,以幫助我們避開(kāi)并發(fā)陷阱,而且因?yàn)榛赽lock滑潘,它能極為簡(jiǎn)單得在不同代碼作用域之間傳遞上下文。
  • 靈活: GCD 具有在常見(jiàn)模式上(比如鎖锨咙、單例)语卤,用更高性能的方法優(yōu)化代碼,而且GCD能提供更多的控制權(quán)力以及大量的底層函數(shù)酪刀。
  • 性能: GCD能自動(dòng)根據(jù)系統(tǒng)負(fù)載來(lái)增減線程數(shù)量粹舵,這就減少了上下文切換以及增加了計(jì)算效率。

相關(guān)概念

GCD中涉及到隊(duì)列骂倘、線程眼滤、串行并行、同步異步历涝、串行并發(fā)等概念诅需,這些概念的認(rèn)知可以通過(guò)我的另一篇文章

  • Dispatch Objects
    盡管GCD是純C語(yǔ)言的,但它被組建成面向?qū)ο蟮娘L(fēng)格荧库。GCD對(duì)象被稱為dispatch object, 所有的dispatch objects都是OC對(duì)象.堰塌,就如其他OC對(duì)象一樣,當(dāng)開(kāi)啟了ARC(automatic reference counting)時(shí),dispatch objects的retain和release都會(huì)自動(dòng)執(zhí)行分衫。而如果是MRC的話场刑,dispatch objects會(huì)使用dispatch_retain和dispatch_release這兩個(gè)方法來(lái)控制引用計(jì)數(shù)。

  • Serial & Concurrent
    串行任務(wù)就是每次只有一個(gè)任務(wù)被執(zhí)行丐箩,并發(fā)任務(wù)就是在同一時(shí)間可以有多個(gè)任務(wù)被執(zhí)行摇邦。

  • Synchronous & Asynchronous
    同步函數(shù)意思是在完成了它預(yù)定的任務(wù)后才返回恤煞,在任務(wù)執(zhí)行時(shí)會(huì)阻塞當(dāng)前線程屎勘。而異步函數(shù)則是任務(wù)會(huì)完成但不會(huì)等它完成施籍,所以異步函數(shù)不會(huì)阻塞當(dāng)前線程,會(huì)繼續(xù)去執(zhí)行下一個(gè)函數(shù)概漱。

  • Concurrency & Parallelism
    并發(fā)的意思就是同時(shí)運(yùn)行多個(gè)任務(wù)丑慎。這些任務(wù)可能是以在單核 CPU 上以分時(shí)(時(shí)間共享)的形式同時(shí)運(yùn)行,也可能是在多核 CPU 上以真正的并行方式來(lái)運(yùn)行瓤摧。然后為了使單核設(shè)備也能實(shí)現(xiàn)這一點(diǎn)竿裂,并發(fā)任務(wù)必須先運(yùn)行一個(gè)線程,執(zhí)行一個(gè)上下文切換照弥,然后運(yùn)行另一個(gè)線程或進(jìn)程腻异。并行則是真正意思上的多任務(wù)同時(shí)運(yùn)行。

  • Context Switch
    Context Switch即上下文切換这揣,一個(gè)上下文切換指當(dāng)你在單個(gè)進(jìn)程里切換執(zhí)行不同的線程時(shí)存儲(chǔ)與恢復(fù)執(zhí)行狀態(tài)的過(guò)程悔常。這個(gè)過(guò)程在編寫(xiě)多任務(wù)應(yīng)用時(shí)很普遍,但會(huì)帶來(lái)一些額外的開(kāi)銷给赞。

  • Dispatch Queues
    GCD dispatch queues是一個(gè)強(qiáng)大的執(zhí)行多任務(wù)的工具机打。Dispatch queue是一個(gè)對(duì)象,它可以接受任務(wù)片迅,并將任務(wù)以先進(jìn)先出(FIFO)的順序來(lái)執(zhí)行残邀。Dispatch queue可以并發(fā)的或串行的執(zhí)行任意一個(gè)代碼塊,而且并發(fā)任務(wù)會(huì)像NSOperationQueue那樣基于系統(tǒng)負(fù)載來(lái)合適地并發(fā)進(jìn)行柑蛇,串行隊(duì)列同一時(shí)間則只執(zhí)行單一任務(wù)芥挣。Dispatch queues內(nèi)部使用的是線程,GCD 管理這些線程耻台,并且使用Dispatch queues的時(shí)候空免,我們都不需要自己創(chuàng)建線程。Dispatch queues相對(duì)于和線程直接通信的代碼優(yōu)勢(shì)是:Dispatch queues使用起來(lái)特別方便粘我,執(zhí)行任務(wù)更加有效率鼓蜒。

具體使用

隊(duì)列

對(duì)了除了串行和并行之分,全局隊(duì)列還有一些相關(guān)屬性影響著隊(duì)列內(nèi)任務(wù)的執(zhí)行征字,比如優(yōu)先級(jí)等都弹,高優(yōu)先級(jí)的隊(duì)列,在等候被調(diào)度的情況下更容易獲取資源或機(jī)會(huì)

  • 串行隊(duì)列
    //主隊(duì)列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
     //自定義的串行隊(duì)列
    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue0", DISPATCH_QUEUE_SERIAL);
  • 并行隊(duì)列
//系統(tǒng)的全局并行隊(duì)列
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
//自定義的并行隊(duì)列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
  • 串行并行的參數(shù)
    DISPATCH_QUEUE_SERIAL  //串行
    DISPATCH_QUEUE_CONCURREN  //并行
  • 全局隊(duì)列的優(yōu)先級(jí)匙姜,默認(rèn)0
#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
任務(wù)
  • 同步任務(wù)
dispatch_sync(globalQueue, ^{
       //同步任務(wù)
    });
  • 異步任務(wù)
dispatch_async(globalQueue, ^{
       //異步任務(wù)
    });
  • dispatch_suspend != 立即停止隊(duì)列的運(yùn)行
    dispatch_suspend畅厢,dispatch_resume提供了“掛起、恢復(fù)”隊(duì)列的功能氮昧,簡(jiǎn)單來(lái)說(shuō)框杜,就是可以暫停浦楣、恢復(fù)隊(duì)列上的任務(wù)。但是dispatch_suspend并不會(huì)立即暫停正在運(yùn)行的block咪辱,而是在當(dāng)前block執(zhí)行完成后振劳,暫停后續(xù)的block執(zhí)行
其他使用
  • DispatchGroup 任務(wù)組
    很多時(shí)候我們需要等待一系列任務(wù)(block)執(zhí)行完成,然后再做一些收尾的工作油狂。如果是有序的任務(wù)历恐,可以分步驟完成的,直接使用串行隊(duì)列就行专筷。但是如果是一系列并行執(zhí)行的任務(wù)弱贼,就需要DispatchGroup 任務(wù)組了
 dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, globalQueue, ^{
        //A
    });
    dispatch_group_async(group, globalQueue, ^{
        //B
    });
    //當(dāng)此group,此隊(duì)列中的所有任務(wù)都結(jié)束才執(zhí)行此block
    dispatch_group_notify(group, globalQueue, ^{
        
    });

  • dispatch_group_enter(group)磷蛹、dispatch_group_leave(group)
    DispatchGroup 任務(wù)組的并發(fā)任務(wù)的情況吮旅,如果此時(shí)拿不到隊(duì)列對(duì)象就沒(méi)法使用dispatch_group_async(group,隊(duì)列),怎么辦呢
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//Enter group
dispatch_group_enter(group);
[manager GET:@"http://www.baidu.com" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    //Deal with result...
    //Leave group
    dispatch_group_leave(group);
}    failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    //Deal with error...
    //Leave group
    dispatch_group_leave(group);
}];
  • 加結(jié)束任務(wù)
    添加結(jié)束任務(wù)也可以分為兩種情況味咳,如下:
    在當(dāng)前線程阻塞的同步等待: dispatch_group_wait(<#dispatch_group_t _Nonnull group#>, <#dispatch_time_t timeout#>)庇勃。
    添加一個(gè)異步執(zhí)行的任務(wù)作為結(jié)束任務(wù):dispatch_group_notify(group, globalQueue, ^{
    });

  • dispatch_barrier_async
    同一個(gè)隊(duì)列,dispatch_barrier_async添加的任務(wù)會(huì)阻塞后面的任務(wù)莺葫,直至此任務(wù)執(zhí)行結(jié)束匪凉;注意:只在自己創(chuàng)建的并發(fā)隊(duì)列上有效

   dispatch_barrier_async(concurrentQueue, ^{
        for (int i=0; i<5; i++) {
            NSLog(@"=%@=====%d",[NSThread currentThread],i);
        }
    });
    dispatch_async(concurrentQueue, ^{
        for (int i=5; i<10; i++) {
            NSLog(@"=%@=====%d",[NSThread currentThread],i);
        }
    });
  • 延時(shí)執(zhí)行 dispatch_after
//主隊(duì)列中的延時(shí)執(zhí)行  時(shí)間單位是dispatch_time_t
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    });
    //任意隊(duì)列中的延時(shí)執(zhí)行
    dispatch_after(DISPATCH_TIME_NOW+30, globalQueue, ^{
        
    });
  • 一次性代碼,單例常用
    dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        //默認(rèn)線程安全
    });
  • 遍歷 讓循環(huán)并行執(zhí)行
    dispatch_apply(10, globalQueue, ^(size_t index) {
        //會(huì)執(zhí)行10次   index順序不確定
    });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捺檬,一起剝皮案震驚了整個(gè)濱河市再层,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌堡纬,老刑警劉巖聂受,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異烤镐,居然都是意外死亡蛋济,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)炮叶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)碗旅,“玉大人,你說(shuō)我怎么就攤上這事镜悉∷畋伲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵侣肄,是天一觀的道長(zhǎng)旧困。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么吼具? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任僚纷,我火速辦了婚禮,結(jié)果婚禮上拗盒,老公的妹妹穿的比我還像新娘怖竭。我一直安慰自己,他們只是感情好锣咒,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布侵状。 她就那樣靜靜地躺著赞弥,像睡著了一般毅整。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绽左,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天悼嫉,我揣著相機(jī)與錄音,去河邊找鬼拼窥。 笑死戏蔑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鲁纠。 我是一名探鬼主播总棵,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼改含!你這毒婦竟也來(lái)了情龄?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捍壤,失蹤者是張志新(化名)和其女友劉穎骤视,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鹃觉,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡专酗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盗扇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祷肯。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖疗隶,靈堂內(nèi)的尸體忽然破棺而出佑笋,到底是詐尸還是另有隱情,我是刑警寧澤抽减,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布允青,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏颠锉。R本人自食惡果不足惜法牲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琼掠。 院中可真熱鬧拒垃,春花似錦、人聲如沸瓷蛙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)艰猬。三九已至横堡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冠桃,已是汗流浹背命贴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留食听,地道東北人胸蛛。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像樱报,于是被迫代替她去往敵國(guó)和親葬项。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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