iOS開發(fā)的中的多線程 --- GCD

多線程實(shí)現(xiàn)的幾種方案

技術(shù)方案 簡介 語言 線程生命周期 使用頻率
pthread 一套通用的多線程方案
適用于Linux、Unix、macOS等平臺
跨平臺/可移植,使用難度大
C 程序員管理 機(jī)會不用
NSThread 蘋果封裝,更加面向?qū)ο?br>簡單使用,可直接操作線程對象 OC 程序員管理 偶爾使用
GCD 旨在替代NSThread多線程技術(shù)
充分利用設(shè)備的多核
C 自動管理 經(jīng)常使用
NSOperation 基于GCD(底層GCD)
但比GCD多了一些更簡單實(shí)用的功能
使用更加面向?qū)ο?/td>
OC 自動管理 經(jīng)常使用

GCD的簡介

GCD中有兩個很重要的概念: 任務(wù) 、隊列。隊列中存放的就是多個任務(wù)隊列的執(zhí)行,就是執(zhí)行其存放的各個任務(wù)

任務(wù):即操作,說白了就是一段代碼塊,在GCD中就是一個block,所以添加任務(wù)十分方便。任務(wù)有同步sync)和異步async)的區(qū)分。主要的區(qū)別在于會不會阻塞當(dāng)前的線程。

  • 同步任務(wù)(sync,即同步操作),它會阻塞當(dāng)前線程,直到block中的任務(wù)執(zhí)行完畢,然后當(dāng)前線程才會繼續(xù)執(zhí)行。
  • 異步任務(wù)(async,即異步操作),它不會阻塞當(dāng)前線程,當(dāng)前線程會直接往下執(zhí)行。

隊列:用于存放任務(wù),決定任務(wù)是順序執(zhí)行的還是并發(fā)執(zhí)行的。隊列對應(yīng)的有兩種:串行隊列并行隊列。

  • 串行隊列,根據(jù)定義,由于是隊列(queue),它遵從隊列的FIFO特性,即按照任務(wù)添加的順序存依次執(zhí)行。
  • 并行隊列,放到并行隊列的任務(wù),GCD 也會 FIFO的取出來,但不同的是,它取出來一個就會放到別的線程,然后再取出來一個又放到另一個的線程。這樣由于取的動作很快,忽略不計,看起來,所有的任務(wù)都是一起執(zhí)行的。不過需要注意,GCD 會根據(jù)系統(tǒng)資源控制并行的數(shù)量,所以如果任務(wù)很多,它并不會讓所有任務(wù)同時執(zhí)行。

線程(thread)與隊列(queue)的關(guān)系:線程隊列是兩個不同的概念。隊列是用來存放任務(wù)的,而線程是由系統(tǒng)去創(chuàng)建和管理,而且一個線程中可能有多個串行并行隊列。

創(chuàng)建隊列

  • 主隊列:這是一個特殊的串行隊列。主隊列用于刷新UI,任何需要刷新UI的工作都是在主隊列中執(zhí)行,所以一般耗時的任務(wù)都是放到別的線程中執(zhí)行。
//獲取主隊列,即主線程
dispatch_queue_t queue = dispatch_get_main_queue();
  • 手動創(chuàng)建隊列:
dispatch_queue_create(const char *_Nullable label,
        dispatch_queue_attr_t _Nullable attr);

其中第一個參數(shù)是標(biāo)識符,用于DEBUG時便于知道是哪個唯一的隊列,可以為空。
第二個參數(shù)用來表示創(chuàng)建的隊列是串行隊列、還是并行隊列
- DISPATCH_QUEUE_SERIAL或者NULL表示創(chuàng)建串行隊列;
- DISPATCH_QUEUE_CONCURRENT表示創(chuàng)建的是并行隊列。

  • 全局并發(fā)隊列:系統(tǒng)提供的一個并發(fā)隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

創(chuàng)建任務(wù)

  • 同步任務(wù):會阻塞當(dāng)前線程(sync
  dispatch_sync(<#queue#>, ^{
      //code here
      NSLog(@"同步任務(wù)");
  });
  • 異步任務(wù):不會阻塞(async
  dispatch_async(<#queue#>, ^{
      //code here
      NSLog(@"異步任務(wù)");
  });

組合代碼測試

  • 同步任務(wù) + 主隊列
    代碼:
//主隊列的任務(wù)(A)
- (void)syncAndMainQueue {
    //同步任務(wù) + 主隊列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0 ; index < 10; index ++) {
        //同步任務(wù)(B)
        dispatch_sync(mainQueue, ^{
            NSLog(@"index : %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打印信息:

同步任務(wù)+主隊列.png

結(jié)論:程序卡死,由于是同步任務(wù)(B),會阻塞當(dāng)前線程,等待加入到線程的同步任務(wù)執(zhí)行完成之后才會繼續(xù)當(dāng)前任務(wù),而由于主隊列是串行隊列,會按按順序(FIFO)執(zhí)行隊列中添加的任務(wù),所以同步任何會等待正在執(zhí)行的任務(wù)執(zhí)行完畢,這樣就造成了相互等待,繼而造成死鎖。

  • 異步任務(wù) + 主隊列
    代碼:
- (void)asyncAndMainQueue {
    //異步任務(wù) + 主隊列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0 ; index < 10; index ++) {
        dispatch_async(mainQueue, ^{
            NSLog(@"index : %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打印信息:


異步任務(wù) + 主隊列.png

結(jié)論:在主線程串行執(zhí)行。由于是異步任務(wù),不會阻塞當(dāng)前線程,由于主隊列是串行隊列,等待當(dāng)前任務(wù)執(zhí)行完成之后按順序執(zhí)行任務(wù)。

  • 同步任務(wù) + 串行隊列
    代碼:
- (void)syncAndSerialQueue {
    //同步任務(wù) + 串行隊列
    dispatch_queue_t serailQueue = dispatch_queue_create("serialQueue", NULL);
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0 ; index < 10; index ++) {
        dispatch_sync(serailQueue, ^{
            NSLog(@"index: %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打?。?/p>

同步任務(wù) + 串行隊列.png

結(jié)論:沒有開啟新線程,在當(dāng)前線程執(zhí)行該同步任務(wù)。由于是同步任務(wù),會阻塞當(dāng)前線程,而隊列是串行隊列,會按順序執(zhí)行任務(wù),等到該隊列中的所有任務(wù)執(zhí)行完畢之后,當(dāng)前線程才會繼續(xù)執(zhí)行下去。

  • 異步任務(wù) + 串行隊列
    代碼:
- (void)asyncAndSerialQueue {
    //異步任務(wù) + 串行隊列
    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0; index < 10; index ++) {
        dispatch_async(serialQueue, ^{
            NSLog(@"index: %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打?。?/p>

異步任務(wù) + 串行隊列.png

結(jié)論:由于是異步任務(wù),不會阻塞當(dāng)前線程,開了新線程,由于是串行隊列,會按順序執(zhí)行任務(wù),所以只需開啟一條新的線程。

  • 同步任務(wù) + 并行隊列
    代碼:
- (void)syncAndConcurrent {
    //同步任務(wù) + 并行隊列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0; index < 10; index ++) {
        dispatch_sync(concurrentQueue, ^{
            NSLog(@"index: %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);    
}

打?。?/p>

同步任務(wù) + 并行隊列.png

結(jié)論:由于是同步任務(wù),會阻塞當(dāng)前線程,且不會開啟新線程,所以同步任務(wù)會在當(dāng)前線程執(zhí)行完畢,等到完畢之后,當(dāng)前線程執(zhí)行執(zhí)行。

  • 異步任務(wù) + 并行隊列
- (void)asyncAndConcurrent {
    //異步任務(wù) + 并行隊列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0; index < 10; index ++) {
        dispatch_async(concurrentQueue, ^{
            NSLog(@"index: %ld --- %@", index, [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打印


異步任務(wù) + 并行隊列.png

結(jié)論:由于是異步任務(wù),不會阻塞當(dāng)前線程,同時會開啟新的線程,而且由于隊列是并行隊列,會開啟多條線程,并發(fā)的執(zhí)行這些異步任務(wù)。

總結(jié)

同步(sync) 異步(async)
串行隊列 當(dāng)前線程,順序執(zhí)行 其他線程,順序執(zhí)行
并行隊列 當(dāng)前線程,順序執(zhí)行 開多個線程,并發(fā)執(zhí)行
主隊列 程序死鎖 主隊列,順序執(zhí)行
    1. 開不開線程,取決于執(zhí)行任務(wù)的函數(shù),同步不開,異步開。
    1. 開幾條線程,取決于隊列,串行開一條,并發(fā)開多條(異步)
    1. 主隊列: 專門用來在主線程上調(diào)度任務(wù)的"隊列",主隊列不能在其他線程中調(diào)度任務(wù)!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文首發(fā)于我的個人博客:「程序員充電站」[https://itcharge.cn]文章鏈接:「傳送門」[https...
    ITCharge閱讀 350,711評論 308 1,927
  • 從哪說起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個最簡單的問題,以這個作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,912評論 1 17
  • iOS多線程編程 基本知識 1. 進(jìn)程(process) 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序,就是一段程序的執(zhí)...
    陵無山閱讀 6,351評論 1 14
  • 兒子從小就乖,聽話,幼兒園、小學(xué)、初中到高中,甚少去做一些違背父母意愿的事情,初、高中階段思想、行為雖有些許叛逆,...
    zwj發(fā)如雪閱讀 253評論 3 8
  • 時光如水,生命如舟,所有人事,都如墜舟之劍,在你不經(jīng)意之時,已經(jīng)一去不復(fù)返,此時再多惋惜與追憶,都是徒然。 01 ...
    阿木拉閱讀 507評論 0 1

友情鏈接更多精彩內(nèi)容