iOS多線程GCD簡(jiǎn)介(一)

之前講過多線程之NSOperation,今天來講講代碼更加簡(jiǎn)潔和高效的GCD。下面說的內(nèi)容都是基于iOS6以后和ARC下。

Grand Central Dispatch (GCD)簡(jiǎn)介

Grand Central Dispatch(GCD) 是異步執(zhí)行任務(wù)的技術(shù)之一。開發(fā)者只需要定義想執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中,GCD就能生成必要的線程并計(jì)劃執(zhí)行任務(wù)。由于線程管理是作為系統(tǒng)的一部分來實(shí)現(xiàn)的,因此可以統(tǒng)一管理,也可執(zhí)行任務(wù),這樣就比以前的線程更有效率。GCD用非常簡(jiǎn)潔的代碼,就可以實(shí)現(xiàn)多線程編程。

這篇主要講Dispatch Queue的一些基本東西,后續(xù)會(huì)加入其他相關(guān)內(nèi)容的介紹。

Dispatch Queue 種類

Dispatch Queue是執(zhí)行處理的等待隊(duì)列,通過調(diào)用dispatch_async等函數(shù),以block的形式將任務(wù)追加到Dispatch Queue中。Dispatch Queue按照添加進(jìn)來的順序(FIFO)執(zhí)行任務(wù)處理。但是在任務(wù)執(zhí)行處理方式上,分為Serial Dispatch QueueConcurrent Dispatch Queue。兩者的區(qū)別如表格所示

Dispatch Queue分類 說明
Serial Dispatch Queue 串行的隊(duì)列,每次只能執(zhí)行一個(gè)任務(wù),并且必須等待前一個(gè)執(zhí)行任務(wù)完成
Concurrent Dispatch Queue 一次可以并發(fā)執(zhí)行多個(gè)任務(wù),不必等待執(zhí)行中的任務(wù)完成

下面用代碼來演示下:

    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    dispatch_async(queue, ^{
        NSLog(@"3");
    });
    dispatch_async(queue, ^{
        NSLog(@"4");
    });

如果上面的queue是Serial Dispatch Queue的話,那么輸出的結(jié)果一定是1,2,3,4。因?yàn)閳?zhí)行順序是確定的,并且后續(xù)的任務(wù)必須在之前的任務(wù)執(zhí)行完成后才能執(zhí)行。

如果是Concurrent Dispatch Queue的話,那么輸出的結(jié)果就不一定是1,2,3,4了。因?yàn)檫@些任務(wù)都是并發(fā)執(zhí)行,并且不需要等待執(zhí)行中的任務(wù)完成,如果其中任意一個(gè)任務(wù)完成將立即執(zhí)行后面的任務(wù)。

Dispatch Queue 創(chuàng)建

在自定義創(chuàng)建前,我們先看看系統(tǒng)為我們提供的幾個(gè)全局的Dispatch Queue:

名稱 Dispatch Queue 的種類 說明
Main Dispatch Queue Serial Dispatch Queue 主線程執(zhí)行
Global Dispatch Queue (HIGH) Concurrent Dispatch Queue 執(zhí)行優(yōu)先級(jí):高
Global Dispatch Queue (DEFAULT) Concurrent Dispatch Queue 執(zhí)行優(yōu)先級(jí):默認(rèn)
Global Dispatch Queue (LOW) Concurrent Dispatch Queue 執(zhí)行優(yōu)先級(jí):低
Global Dispatch Queue (BACKGROUND) Concurrent Dispatch Queue 執(zhí)行優(yōu)先級(jí):后臺(tái)

從表格中我們可以知道我們的主線程就是Serial Dispatch Queue,而之后的三種Dispatch Queue 則是Concurrent Dispatch Queue。這也是為什么我們不能把耗時(shí)的任務(wù)放在主線程里面去操作。

如果沒有特殊需求,我們可以直接獲取這些queue來執(zhí)行我們的任務(wù):

//主線程
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
//HIGH
    dispatch_queue_t highQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//DEFAULT
    dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//LOW
    dispatch_queue_t lowQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
//BACKGROUND
    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

下面看看如何自定義一個(gè)queue:

//串行隊(duì)列
    dispatch_queue_t serialQueue = dispatch_queue_create("com.gcd.serialQueue", DISPATCH_QUEUE_SERIAL);
//并發(fā)隊(duì)列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.gcd.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

通過調(diào)用dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)這個(gè)函數(shù)。第一個(gè)參數(shù)是給這個(gè)queue起的標(biāo)識(shí),這個(gè)在調(diào)試的可以看到是哪個(gè)隊(duì)列在執(zhí)行,或者在crash日志中,也能做為提示。第二個(gè)是需要?jiǎng)?chuàng)建的隊(duì)列類型,是串行的還是并發(fā)的。當(dāng)然你也可以通過dispatch_queue_get_label(dispatch_queue_t queue)獲取你創(chuàng)建queue的名字。

使用

  • 異步執(zhí)行

這個(gè)也是我們使用最多的地方,我們直接調(diào)用dispatch_async這個(gè)函數(shù),就可以將我們要追加的任務(wù)添加到隊(duì)列里面,并立即返回,異步的執(zhí)行。這個(gè)不多講。

dispatch_async(queue, ^{
        NSLog(@"1");
    });
  • 同步執(zhí)行

這點(diǎn)我們可能用得不是很多,但是一用不好就出現(xiàn)問題了。當(dāng)調(diào)用這個(gè)dispatch_sync函數(shù)的時(shí)候,這個(gè)線程將不會(huì)立即返回,直到這個(gè)線程執(zhí)行完畢??聪孪旅娴拇a:

dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"2");
    });

如果你在主線程里面調(diào)用這個(gè)函數(shù),那么,很遺憾,主線程將被卡主3秒鐘。當(dāng)主線程調(diào)用這個(gè)方法的時(shí)候,由于是同步,不會(huì)立即返回,直到這個(gè)里面內(nèi)容執(zhí)行完畢才能返回。這個(gè)時(shí)候不管你這個(gè)queue是什么類型,都一樣。既然不能立即返回,我們可以在一個(gè)異步執(zhí)行的線程中,再去調(diào)用這個(gè)同步方法。

dispatch_async(serialQueue, ^{
        NSLog(@"4");
        dispatch_sync(queue, ^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"5");
        });
        NSLog(@"6");
    });

那這個(gè)時(shí)候,調(diào)用這個(gè)方法的時(shí)候這個(gè)線程將立即返回。而同步在這個(gè)線程里面執(zhí)行。這個(gè)時(shí)候?qū)⑤敵觯?,5,6的結(jié)果。

同步執(zhí)行的死鎖問題

現(xiàn)在把上面代碼拿出來改下


dispatch_async(serialQueue, ^{
        NSLog(@"4");
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"5");
        });
        NSLog(@"6");
    });

這個(gè)時(shí)候,我把queue的類型設(shè)置為串行的類型。這個(gè)時(shí)候?qū)⒅粫?huì)輸出4。為什么呢?系統(tǒng)調(diào)用這個(gè)線程的時(shí)候,首先輸出4,然后繼續(xù)執(zhí)行這個(gè)里面的同步線程。由于我的這個(gè)queue是串行的,也就是后續(xù)的任務(wù)必須在之前的執(zhí)行中任務(wù)完成后才能繼續(xù)執(zhí)行。但是這個(gè)同步執(zhí)行的線程不會(huì)立即返回,必須等到它執(zhí)行完成才能返回。這樣最外面的任務(wù)沒法執(zhí)行完,而里面的同步線程又不能立即返回,所以就形成了死鎖。

因此在你的編程中使用這個(gè)API的時(shí)候,一定要當(dāng)心,不然就會(huì)形成死鎖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 本篇博客共分以下幾個(gè)模塊來介紹GCD的相關(guān)內(nèi)容: 多線程相關(guān)概念 多線程編程技術(shù)的優(yōu)缺點(diǎn)比較? GCD中的三種隊(duì)列...
    有夢(mèng)想的老伯伯閱讀 1,084評(píng)論 0 4
  • iOS 多線程系列 -- 基礎(chǔ)概述iOS 多線程系列 -- pthreadiOS 多線程系列 -- NSThrea...
    shannoon閱讀 987評(píng)論 0 2
  • 程序中同步和異步是什么意思?有什么區(qū)別? 解釋一:異步調(diào)用是通過使用單獨(dú)的線程執(zhí)行的。原始線程啟動(dòng)異步調(diào)用,異步調(diào)...
    風(fēng)繼續(xù)吹0閱讀 1,109評(píng)論 1 2
  • 目錄 一、基本概念1.多線程2.串行和并行, 并發(fā)3.隊(duì)列與任務(wù)4.同步與異步5.線程狀態(tài)6.多線程方案 二、GC...
    BohrIsLay閱讀 1,692評(píng)論 5 12
  • 從哪說起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個(gè)最簡(jiǎn)單的問題,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,902評(píng)論 1 17

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