iOS多線程編程之GCD

文章資料來源《Objective-C高級(jí)編程》之GCD

GCD是一種異步執(zhí)行任務(wù)的技術(shù),對(duì)于編程層面上異步執(zhí)行就意味著創(chuàng)建一個(gè)線程(操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位谱醇,是進(jìn)程中一個(gè)單一順序的控制流--from wiki)去執(zhí)行Task醇疼;GCD提供了兩種隊(duì)列和相關(guān)API使得開發(fā)者只需要關(guān)心該選擇哪種隊(duì)列去執(zhí)行任務(wù)即可;

GCD的隊(duì)列

  • serial queue 能夠保證各個(gè)task在同一個(gè)線程中被執(zhí)行并且執(zhí)行順序會(huì)嚴(yán)格的按照入隊(duì)的順序進(jìn)行听想;
  • concurrent queue 各個(gè)task的執(zhí)行互不影響掏秩,執(zhí)行順序上不確定,執(zhí)行線程也不一定會(huì)相同兴喂;
dispatch_queue_create 創(chuàng)建隊(duì)列

serial queue

  /*
 1>serial Queue:系統(tǒng)默認(rèn)創(chuàng)建一個(gè)線程蔼囊,隊(duì)列中的任務(wù)是順序執(zhí)行
 2>創(chuàng)建多個(gè)serial queue 的執(zhí)行是并發(fā)的沒有順序
 3>解決數(shù)據(jù)競爭問題:可以將任務(wù)放在serial queue中 保證任務(wù)按照順序執(zhí)行就能解決數(shù)據(jù)競爭
*/
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.hua.example.serialQueue", DISPATCH_QUEUE_SERIAL);

concurrent queue

 /*
  1 concurrent queue 添加到隊(duì)列中的任務(wù)會(huì)并發(fā)執(zhí)行,沒有順序性
 */
dispatch_queue_t myConcurrentQueue=dispatch_queue_create("com.hua.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

非ARC下生成的隊(duì)列還必須使用dispatch_release(Queue);來釋放指定的隊(duì)列

Main Dispatch Queue and Global Dispatch Queue

Main Dispatch Queue

  /*
  dispatch_get_main_queue
 (1)main queue 是一中serial queue衣迷,task是放在主線程的Runloop中執(zhí)行的畏鼓;
 (2)一些UI的更新操作需要放在主線程中,使用main queue是比較簡單的
 */
dispatch_queue_t main_queue = dispatch_get_main_queue();

global Dispatch Queue

 /*
   dispatch_get_global_queue
 (1)global queue 是一種concurrent queue壶谒,可以通過設(shè)置queue的priority指定執(zhí)行的優(yōu)先級(jí)云矫;
 */
dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  

dispatch_set_target_queue

 /*
 dispatch_set_target_queue的第一個(gè)參數(shù)是指定要變更優(yōu)先級(jí)的隊(duì)列;指定與要使用優(yōu)先級(jí)相同優(yōu)先級(jí)的隊(duì)列為第二個(gè)參數(shù)
 */
dispatch_queue_t serialqueue1 = dispatch_queue_create("serialqueue1", NULL);
dispatch_queue_t serialqueue2 = dispatch_queue_create("serialqueue2", NULL);
dispatch_set_target_queue(serialqueue2, serialqueue1);
/*  

dispatch_after

/*
  延遲若干時(shí)間處理某一個(gè)Task汗菜,只是追加task到某一個(gè)隊(duì)列让禀,并不一定立即執(zhí)行task
*/
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
    NSLog(@"wait at least three seconds!!");
});

dispatch Group

dispatch group 的出現(xiàn)可以解決多個(gè)并發(fā)task執(zhí)行后能收到通知再執(zhí)行其他任務(wù)操作的需求;

  /*
  1; 如果使用 serial queue 所有的task執(zhí)行完畢后在執(zhí)行done task
  2:如果使用 concurrent queue 所有的task執(zhí)行后沒辦法 執(zhí)行行done task 就需要 dispatch_group
 */
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
//
dispatch_group_async(group, queue, ^{
    NSLog(@"blok1");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"blok2");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"blok3");
});
dispatch_group_async(group, queue, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"blok4");
});
// 監(jiān)聽group 中的task 是否已經(jīng)全部執(zhí)行完成
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"done!!");
});
//   dispatch_group_wait會(huì)hold住當(dāng)前線程直到所有task執(zhí)行完畢
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

NSLog(@"all finish!!!!");

多個(gè)網(wǎng)絡(luò)請(qǐng)求執(zhí)行操作完成在執(zhí)行下一步操作的需求如何實(shí)現(xiàn)陨界?

 // 多個(gè)網(wǎng)絡(luò)請(qǐng)求完成后再做新的任務(wù)
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //網(wǎng)絡(luò)請(qǐng)求操作1
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //網(wǎng)絡(luò)請(qǐng)求操作2
        dispatch_group_leave(group);
    });

dispatch_barrier_async

多線程操作產(chǎn)生的一個(gè)問題就是數(shù)據(jù)資源的競爭巡揍,讀寫操作如何能保證線程安全性;dispatch_barrier_async提供了解決方案

 /*
   使用concurrent dispatch queue 和 dispatch barrier async 函數(shù)可實(shí)現(xiàn)高效率的數(shù)據(jù)庫訪問和文件讀取
 */
dispatch_queue_t queue = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    NSLog(@"task1forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task2forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task3forReading!");
});
dispatch_barrier_async(queue, ^{
    // 此taskforWriting 會(huì)等到加入concurrentQueue中的task執(zhí)行完畢后菌瘪,執(zhí)行taskforWriting腮敌,等到該taskforWriting執(zhí)行完畢后在執(zhí)行 concurrentQueue中的task
    NSLog(@"taskforWriting!");
});
dispatch_async(queue, ^{
    NSLog(@"task4forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task5forReading!");
});

dispatch_sync

/*
dispatch_sync 函數(shù)意味著等待;它要等待task執(zhí)行完畢后再做返回
*/
//使用dispatch_sync 容易造成死鎖
//在主線程中執(zhí)行以下源代碼會(huì)造成死鎖
/*
  main_queue 是一個(gè)serialQueue 俏扩,使用dispatch_sync將task加入到mainqueue中task會(huì)等待mainqueue中的任務(wù)執(zhí)行完成糜工,而mainqueue又要等待task完成,由此造成了死鎖录淡;
 */
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_sync(main_queue, ^{
    NSLog(@"hello dispatch_sync!");
});
//>2在主線程中執(zhí)行以下源代碼也會(huì)造成死鎖
dispatch_async(main_queue, ^{
   dispatch_sync(main_queue, ^{
       NSLog(@"hello!!");
   });
});

dispatch_apply

  NSMutableArray* tempArr  = [@[@"key1",@"key2",@"key3",@"key4",@"key5"] mutableCopy];
   // 1 按照指定的次數(shù)將指定的Block追加到指定的Dispatch_Queue中捌木,并等待全部處理執(zhí)行結(jié)束
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply([tempArr count], queue, ^(size_t index) {
        // 要做數(shù)據(jù)更新操作
        NSLog(@"%d",index);
    });
    NSLog(@"task done");
    /*
     1 對(duì)數(shù)組進(jìn)行循環(huán)遍歷的方法
       1》 for循環(huán)
       2》 block
       3》 dispatch_apply
      2 dispatch_apply 要等待結(jié)束,最好和 dispatch_async函數(shù)混合使用
     */

掛起隊(duì)列和執(zhí)行隊(duì)列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//掛起隊(duì)列
dispatch_suspend(queue);
//恢復(fù)指定隊(duì)列
dispatch_resume(queue);  

dispatch_Semaphore

 // 1  向數(shù)組中增加對(duì)象由于內(nèi)存錯(cuò)誤導(dǎo)致異常的概率會(huì)很高
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray* mutable_arr =[NSMutableArray array];
for(int i = 0;i<100000;++i)
{
   dispatch_async(queue, ^{
       [mutable_arr addObject:[NSNumber numberWithInt:i]];
   });
}


// 2 使用dispatch_semaphore進(jìn)行更細(xì)粒度的線程管理
dispatch_queue_t global_queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
  生成Dispatch Semahpore
  dispatch_Semahpore 的計(jì)數(shù)初始值設(shè)定為“1”
  這樣能保證訪問NSMutableArray類對(duì)象的線程嫉戚,同時(shí)只有1個(gè)
 */
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray* array =[NSMutableArray array];
for(int i = 0;i<10000;i++)
{
    dispatch_async(global_queue, ^{
        /*
         等待Dispatch Semaphore
         直到Dispatch Semphore的計(jì)數(shù)值達(dá)到大于等于1刨裆;
         */
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        /*
         由于dispatch Semaphore 的計(jì)數(shù)值達(dá)到大于等于1
         所以將Dispatch semaphore 的計(jì)數(shù)值減去1
         dispatch_semaphore_wait 函數(shù)執(zhí)行返回
         執(zhí)行到此 dispatch Semaphore的計(jì)數(shù)值恒為“0”
         */
        
        [array addObject:[NSNumber numberWithInt:i]];
        
        /*
         排他控制處理結(jié)束,所以通過dispatch_semaphore_signal函數(shù) 將
         Dispatch Semaphore的計(jì)數(shù)值加1
         如果有通過dispatch_semaphore_wait 函數(shù) 等待dispatch Semaphore 的計(jì)數(shù)值增加的線程 就由最先等待的線程執(zhí)行
         */
        dispatch_semaphore_signal(semaphore);

    });
}

dispatch_once

保證應(yīng)用程序中只執(zhí)行一次指定處理的API

 +(instancetype)shareInstance
    {
        static ViewController* _vc;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _vc =[[self alloc] init];
        });
        return _vc;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末彼水,一起剝皮案震驚了整個(gè)濱河市崔拥,隨后出現(xiàn)的幾起案子极舔,更是在濱河造成了極大的恐慌凤覆,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拆魏,死亡現(xiàn)場離奇詭異盯桦,居然都是意外死亡慈俯,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門拥峦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贴膘,“玉大人,你說我怎么就攤上這事略号⌒滔浚” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵玄柠,是天一觀的道長突梦。 經(jīng)常有香客問我,道長羽利,這世上最難降的妖魔是什么宫患? 我笑而不...
    開封第一講書人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮这弧,結(jié)果婚禮上娃闲,老公的妹妹穿的比我還像新娘。我一直安慰自己匾浪,他們只是感情好皇帮,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蛋辈,像睡著了一般玲献。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梯浪,一...
    開封第一講書人閱讀 49,850評(píng)論 1 290
  • 那天捌年,我揣著相機(jī)與錄音,去河邊找鬼挂洛。 笑死礼预,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的虏劲。 我是一名探鬼主播托酸,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼柒巫!你這毒婦竟也來了励堡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤堡掏,失蹤者是張志新(化名)和其女友劉穎应结,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹅龄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年揩慕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扮休。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡迎卤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出玷坠,到底是詐尸還是另有隱情蜗搔,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布八堡,位于F島的核電站碍扔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏秕重。R本人自食惡果不足惜不同,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望溶耘。 院中可真熱鬧二拐,春花似錦、人聲如沸凳兵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽庐扫。三九已至饭望,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間形庭,已是汗流浹背铅辞。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萨醒,地道東北人斟珊。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像富纸,于是被迫代替她去往敵國和親囤踩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

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

  • 1. GCD簡介 iOS開發(fā)中多線程的API主要有pthread晓褪,NSThread堵漱,NSOperation和GCD...
    安東_Ace閱讀 1,255評(píng)論 0 6
  • 本文的寫作目的是為學(xué)習(xí)記錄,同時(shí)分享給大家涣仿,希望大神能夠?qū)ξ闹绣e(cuò)誤的理解進(jìn)行指正勤庐。 如果文章內(nèi)容涉及到其他已經(jīng)發(fā)表...
    油菜小白閱讀 676評(píng)論 0 2
  • 本篇博客共分以下幾個(gè)模塊來介紹GCD的相關(guān)內(nèi)容: 多線程相關(guān)概念 多線程編程技術(shù)的優(yōu)缺點(diǎn)比較? GCD中的三種隊(duì)列...
    有夢(mèng)想的老伯伯閱讀 1,018評(píng)論 0 4
  • GCD(Grand Central Dispatch)是iOS多任務(wù)的核心,它可以讓程序員不用直接參與到線程的創(chuàng)建...
    koce_zhao閱讀 267評(píng)論 0 1
  • 去上海是清明前一周定下來的埃元,雖然老公頗有微詞涝涤,他認(rèn)為我們應(yīng)該選一個(gè)有山有水媚狰,慢節(jié)奏適合自駕的地方去度假岛杀。但扛...
    limingzhuo閱讀 260評(píng)論 0 0