iOS多線程-GCD使用總結(jié)

寫(xiě)在前面:

GCD祖凫,它是基于C語(yǔ)言的API寝杖,開(kāi)發(fā)者只需要將任務(wù)放在block內(nèi)型豁,并指定好追加的隊(duì)列僵蛛,就可以完成多線程開(kāi)發(fā)。屬于系統(tǒng)級(jí)的線程管理迎变,在Dispatch queue中執(zhí)行需要執(zhí)行的任務(wù)性能非常的高充尉。以下為個(gè)人的學(xué)習(xí)筆記,大神略過(guò)衣形!

隊(duì)列

隊(duì)列:Dispatch Queue是執(zhí)行處理的等待隊(duì)列驼侠,按照任務(wù)(block)追加到隊(duì)列里的順序,并遵循FIFO執(zhí)行處理

  • 隊(duì)列分為串行隊(duì)列和并行隊(duì)列谆吴。
    • Serial Dispatch Queue:串行隊(duì)列倒源,等待當(dāng)前執(zhí)行任務(wù)處理結(jié)束的隊(duì)列。
      - (void)gcd_serialQueue
      {
       //第一個(gè)函數(shù)為隊(duì)列的名稱句狼,
      // 第二個(gè)參數(shù)是NULL和DISPATCH_QUEUE_SERIAL時(shí)笋熬,返回的隊(duì)列就是串行隊(duì)列。
         dispatch_queue_t queue = dispatch_queue_create("serial queue", NULL);
          for (NSInteger i = 0; i < 10; i ++) {
              dispatch_async(queue, ^{
                 NSLog(@"serial queue :%ld",i);
             });
         }
     }   
    
    輸出:
     Study_GCD[46280:2496418] serial queue :0
     Study_GCD[46280:2496418] serial queue :1
     Study_GCD[46280:2496418] serial queue :2
     Study_GCD[46280:2496418] serial queue :3
     Study_GCD[46280:2496418] serial queue :4
     Study_GCD[46280:2496418] serial queue :5
     Study_GCD[46280:2496418] serial queue :6
     Study_GCD[46280:2496418] serial queue :7
     Study_GCD[46280:2496418] serial queue :8
     Study_GCD[46280:2496418] serial queue :9
    
    • Concurrent Dispatch Queue:并發(fā)隊(duì)列腻菇,不等待當(dāng)前執(zhí)行任務(wù)處理結(jié)束的隊(duì)列胳螟。
      - (void)gcd_concurrentQueue
      {
         dispatch_queue_t queue = dispatch_queue_create("concurrent queue", DISPATCH_QUEUE_CONCURRENT);
          for (NSInteger i = 0; i < 6; i ++) {
            dispatch_async(queue, ^{
             NSLog(@"concurrent queue %ld ",i);
             });
         }
      }
    

輸出:

     Study_GCD[46343:2501196] concurrent queue 0 
     Study_GCD[46343:2501197] concurrent queue 3 
     Study_GCD[46343:2501215] concurrent queue 2 
     Study_GCD[46343:2501214] concurrent queue 1 
     Study_GCD[46343:2501199] concurrent queue 4 
     Study_GCD[46343:2501217] concurrent queue 5 
  • 放入串行隊(duì)列的任務(wù)將會(huì)在主線程執(zhí)行,執(zhí)行順序是按照順序執(zhí)行筹吐。
  • 放入并行隊(duì)列的任務(wù)會(huì)在子線程執(zhí)行糖耸,執(zhí)行順序是并行執(zhí)行。
主線程&子線程

主線程:負(fù)責(zé)執(zhí)行UI活動(dòng)丘薛,絕大部分的UI活動(dòng)都要在這里調(diào)用嘉竟,不能讓其阻塞,要將耗時(shí)的任務(wù)放到子線程來(lái)做。
子線程:負(fù)責(zé)執(zhí)行耗時(shí)的運(yùn)算周拐,網(wǎng)絡(luò)請(qǐng)求等不能放在主線程的任務(wù)铡俐。

系統(tǒng)為我們提供了共用的主隊(duì)列(Main Dispatch Queue)和全局并行隊(duì)列(Global Dispatch Queue)。我們只需將需要執(zhí)行的任務(wù)放入到這兩類隊(duì)列里就可以實(shí)現(xiàn)多線程編程妥粟。

系統(tǒng)提供的隊(duì)列

Main Dispatch Queue

  • 主隊(duì)列:
    放在這個(gè)隊(duì)列里的任務(wù)會(huì)追加到主線程的RunLoop中執(zhí)行审丘。需要刷新UI的時(shí)候我們可以直接獲取這個(gè)隊(duì)列,將任務(wù)追加到這個(gè)隊(duì)列中勾给。
dispatch_queue_t mainQ = dispatch_get_main_queue();
NSOperationQueue *mainQ = [NSOperationQueue mainQueue];
  • 獲取主隊(duì)列并布置任務(wù)
//NSThread
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

//GCD
 dispatch_async(dispatch_get_main_queue(), ^{                   

                        [doSomething];

                    });

Globle Dispatch Queue

  • 全局并發(fā)隊(duì)列:
    開(kāi)發(fā)者可以不需要特意通過(guò)dispatch_queue_create方法創(chuàng)建一個(gè)Concurrent Dispatch Queue滩报,可以將任務(wù)直接放在這個(gè)全局并發(fā)隊(duì)列里面。
dispatch queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
  • 獲取全局并行隊(duì)列并布置任務(wù)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

          [doSomething];
 });

線程通訊

很多情況下播急,我們需要在子線程進(jìn)行下載任務(wù)脓钾,下載完成后在主線程更新UI,這時(shí)候就需要線程之間的通信:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

              //下載圖片
              NSData *dataFromURL = [NSData dataWithContentsOfURL:imageURL];
              UIImage *imageFromData = [UIImage imageWithData:dataFromURL];

      dispatch_async(dispatch_get_main_queue(), ^{

              //加載完成更新view
              UIImageView *imageView = [[UIImageView alloc] initWithImage:imageFromData];

      });

  });
//在這里桩警,我們?cè)谌植⑿嘘?duì)列的回調(diào)block里調(diào)用了主線程可训,并在主線程里執(zhí)行了UI操作。

dispatch_group

需求點(diǎn):執(zhí)行多個(gè)耗時(shí)的異步任務(wù)捶枢,但是只能等到這些任務(wù)都執(zhí)行完畢后握截,才能在主線程執(zhí)行某個(gè)任務(wù)。

為了實(shí)現(xiàn)這個(gè)需求烂叔,我們需要讓將這些異步執(zhí)行的操作放在

  • dispatch_group_async函數(shù)中執(zhí)行谨胞,最后再調(diào)用,
  • dispatch_group_notify來(lái)執(zhí)行最后執(zhí)行的任務(wù)蒜鸡。
 dispatch_group_t group =  dispatch_group_create();
  dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      // 執(zhí)行1個(gè)耗時(shí)的異步操作
  });

  dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      // 執(zhí)行1個(gè)耗時(shí)的異步操作
  });

  dispatch_group_notify(group, dispatch_get_main_queue(), ^{
      // 等前面的異步操作都執(zhí)行完畢后胯努,回到主線程...
  });

dispatch_after

  • 在某個(gè)線程里,在指定的時(shí)間后處理某個(gè)任務(wù):
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"2秒之后追加到隊(duì)列");
});

dispatch_barrier_async

  • 關(guān)于解決數(shù)據(jù)競(jìng)爭(zhēng)的方法:讀取處理是可以并發(fā)的逢防,但是寫(xiě)入處理卻是不允許并發(fā)執(zhí)行的叶沛。
  • 讀取處理追加到concurrent dispatch queue中
  • 寫(xiě)入處理在任何一個(gè)讀取處理沒(méi)有執(zhí)行的狀態(tài)下,追加到serial dispatch queue中(也就是說(shuō)忘朝,在寫(xiě)入處理結(jié)束之前灰署,讀取處理不可執(zhí)行)。

需求點(diǎn):雖然我們有時(shí)要執(zhí)行幾個(gè)不同的異步任務(wù)辜伟,但是我們還是要將其分成兩組:當(dāng)?shù)谝唤M異步任務(wù)都執(zhí)行完成后才執(zhí)行第二組的異步任務(wù)氓侧。這里的組可以包含一個(gè)任務(wù)脊另,也可以包含多個(gè)任務(wù)导狡。

為了實(shí)現(xiàn)這個(gè)需求,我們需要使用dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);在兩組任務(wù)之間形成“柵欄”偎痛,使其“下方”的異步任務(wù)在其“上方”的異步任務(wù)都完成之前是無(wú)法執(zhí)行的旱捧。

 dispatch_queue_t queue = dispatch_queue_create("1122333", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"----任務(wù) 1-----");
    });

    dispatch_async(queue, ^{
        NSLog(@"----任務(wù) 2-----");
    });    

    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----");
    });

    dispatch_async(queue, ^{
        NSLog(@"----任務(wù) 3-----");
    });

    dispatch_async(queue, ^{
        NSLog(@"----任務(wù) 4-----");
    });

輸出

Study_GCD[46399:2506252] ----任務(wù) 2-----
Study_GCD[46399:2506249] ----任務(wù) 1-----
Study_GCD[46399:2506249] ----barrier-----
Study_GCD[46399:2506249] ----任務(wù) 3-----
Study_GCD[46399:2506252] ----任務(wù) 4-----

dispatch_sync

  • dispatch_async:異步函數(shù),這個(gè)函數(shù)會(huì)立即返回,不做任何等待枚赡,它所指定的block“非同步地”追加到指定的隊(duì)列中氓癌。
  • dispatch_sync:同步函數(shù),這個(gè)函數(shù)不會(huì)立即返回贫橙,它會(huì)一直等待追加到特定隊(duì)列中的制定block完成工作后才返回贪婉,所以它的目的(也是效果)是阻塞當(dāng)前線程。(開(kāi)發(fā)中切記注意!)

dispatch_once (一次性任務(wù))

  • 通過(guò)dispatch_once處理的代碼只執(zhí)行一次卢肃,而且是線程安全的:
- (void)gcd_dispatch_once_1
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (NSInteger index = 0; index < 5; index++) {
        
        dispatch_async(queue, ^{
            [self gcd_onceCode];
        });
    }
}


- (void)gcd_onceCode
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"只執(zhí)行一次的代碼");
    });
}

輸出:

Study_GCD[46436:2509090] 只執(zhí)行一次的代碼

參考內(nèi)容:

http://libdispatch.macosforge.org

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疲迂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子莫湘,更是在濱河造成了極大的恐慌尤蒿,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幅垮,死亡現(xiàn)場(chǎng)離奇詭異腰池,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)忙芒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)示弓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人匕争,你說(shuō)我怎么就攤上這事避乏。” “怎么了甘桑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拍皮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我跑杭,道長(zhǎng)铆帽,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任德谅,我火速辦了婚禮爹橱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘窄做。我一直安慰自己愧驱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布椭盏。 她就那樣靜靜地躺著组砚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掏颊。 梳的紋絲不亂的頭發(fā)上糟红,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天艾帐,我揣著相機(jī)與錄音,去河邊找鬼盆偿。 笑死柒爸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的事扭。 我是一名探鬼主播捎稚,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼求橄!你這毒婦竟也來(lái)了阳藻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谈撒,失蹤者是張志新(化名)和其女友劉穎腥泥,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體啃匿,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛔外,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了溯乒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夹厌。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖裆悄,靈堂內(nèi)的尸體忽然破棺而出矛纹,到底是詐尸還是另有隱情,我是刑警寧澤光稼,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布或南,位于F島的核電站,受9級(jí)特大地震影響艾君,放射性物質(zhì)發(fā)生泄漏采够。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一冰垄、第九天 我趴在偏房一處隱蔽的房頂上張望蹬癌。 院中可真熱鬧,春花似錦虹茶、人聲如沸逝薪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)董济。三九已至,卻和暖如春洲炊,著一層夾襖步出監(jiān)牢的瞬間感局,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工暂衡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留询微,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓狂巢,卻偏偏與公主長(zhǎng)得像撑毛,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唧领,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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