iOS多線程GCD簡介(一)

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

Grand Central Dispatch (GCD)簡介

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

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

Dispatch Queue 種類

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

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

下面用代碼來演示下:

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

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

如果是Concurrent Dispatch Queue的話,那么輸出的結果就不一定是1,2,3,4了。因為這些任務都是并發(fā)執(zhí)行,并且不需要等待執(zhí)行中的任務完成,如果其中任意一個任務完成將立即執(zhí)行后面的任務。

Dispatch Queue 創(chuàng)建

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

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

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

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

//主線程
    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);

下面看看如何自定義一個queue:

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

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

使用

  • 異步執(zhí)行

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

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

這點我們可能用得不是很多,但是一用不好就出現問題了。當調用這個dispatch_sync函數的時候,這個線程將不會立即返回,直到這個線程執(zhí)行完畢??聪孪旅娴拇a:

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

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

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

那這個時候,調用這個方法的時候這個線程將立即返回。而同步在這個線程里面執(zhí)行。這個時候將輸出,4,5,6的結果。

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

現在把上面代碼拿出來改下


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

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

因此在你的編程中使用這個API的時候,一定要當心,不然就會形成死鎖。

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

相關閱讀更多精彩內容

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

友情鏈接更多精彩內容