ios GCD 詳解

1. GCD簡介

Grand Central Dispatch (GCD) 是Apple開發的一個多核編程的較新的解決方法。它主要用於優化應用程序以支持多核處理器以及其他對稱多處理系統。它是一個在線程池模式的基礎上執行的並行任務。在Mac OS X 10.6雪豹中首次推出,也可在IOS 4及以上版本使用。

爲什麼要用GCD呢?

因爲GCD有很多好處啊,具體如下:

  • GCD可用於多核的並行運算
  • GCD會自動利用更多的CPU內核(比如雙核、四核)
  • GCD會自動管理線程的生命週期(創建線程、調度任務、銷燬線程)
  • 程序員只需要告訴GCD想要執行什麼任務,不需要編寫任何線程管理代碼

既然GCD有這麼多的好處,那麼下面我們就來系統的學習一下GCD的使用方法。

2. 任務和隊列

學習GCD之前,先來了解GCD中兩個核心概念:任務和隊列。

任務:就是執行操作的意思,換句話說就是你在線程中執行的那段代碼。在GCD中是放在block中的。執行任務有兩種方式:同步執行異步執行。兩者的主要區別是:是否具備開啓新線程的能力。

  • 同步執行(sync):只能在當前線程中執行任務,不具備開啓新線程的能力
  • 異步執行(async):可以在新的線程中執行任務,具備開啓新線程的能力

隊列:這裏的隊列指任務隊列,即用來存放任務的隊列。隊列是一種特殊的線性表,採用FIFO(先進先出)的原則,即新任務總是被插入到隊列的末尾,而讀取任務的時候總是從隊列的頭部開始讀取。每讀取一個任務,則從隊列中釋放一個任務。在GCD中有兩種隊列:串行隊列並行隊列

  • 並行隊列(Concurrent Dispatch Queue):可以讓多個任務並行(同時)執行(自動開啓多個線程同時執行任務)
    • 並行功能只有在異步(dispatch_async)函數下才有效
  • 串行隊列(Serial Dispatch Queue):讓任務一個接着一個地執行(一個任務執行完畢後,再執行下一個任務)

3. GCD的使用步驟

GCD的使用步驟其實很簡單,只有兩步。

  1. 創建一個隊列(串行隊列或並行隊列)
  2. 將任務添加到隊列中,然後系統就會根據任務類型執行任務(同步執行或異步執行)

下邊來看看隊列的創建方法和任務的創建方法。

1. 隊列的創建方法

  • 可以使用dispatch_queue_create來創建對象,需要傳入兩個參數,第一個參數表示隊列的唯一標識符,用於DEBUG,可爲空;第二個參數用來識別是串行隊列還是並行隊列。DISPATCH_QUEUE_SERIAL表示串行隊列,DISPATCH_QUEUE_CONCURRENT表示並行隊列。
// 串行隊列的創建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
// 並行隊列的創建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
  • 對於並行隊列,還可以使用dispatch_get_global_queue來創建全局並行隊列。GCD默認提供了全局的並行隊列,需要傳入兩個參數。第一個參數表示隊列優先級,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT。第二個參數暫時沒用,用0即可。

2. 任務的創建方法

// 同步執行任務創建方法
dispatch_sync(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);    // 這裏放任務代碼
});
// 異步執行任務創建方法
dispatch_async(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);    // 這裏放任務代碼
});

雖然使用GCD只需兩步,但是既然我們有兩種隊列,兩種任務執行方式,那麼我們就有了四種不同的組合方式。這四種不同的組合方式是

  1. 並行隊列 + 同步執行
  2. 並行隊列 + 異步執行
  3. 串行隊列 + 同步執行
  4. 串行隊列 + 異步執行

實際上,我們還有一種特殊隊列是主隊列,那樣就有六種不同的組合方式了。

  1. 主隊列 + 同步執行
  2. 主隊列 + 異步執行

那麼這幾種不同組合方式各有什麼區別呢,這裏爲了方便,先上結果,再來講解。爲圖省事,直接查看錶格結果,然後可以跳過** 4. GCD的基本使用** 了。

 並行隊列串行隊列主隊列
同步(sync)沒有開啓新線程,串行執行任務沒有開啓新線程,串行執行任務沒有開啓新線程,串行執行任務
異步(async)有開啓新線程,並行執行任務有開啓新線程(1條),串行執行任務沒有開啓新線程,串行執行任務

下邊我們來分別講講這幾種不同的組合方式的使用方法。

4. GCD的基本使用

先來講講並行隊列的兩種使用方法。

1. 並行隊列 + 同步執行

  • 不會開啓新線程,執行完一個任務,再執行下一個任務
- (void) syncConcurrent
{
    NSLog(@"syncConcurrent---begin");

    dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"syncConcurrent---end");
}

輸出結果:
2016-09-03 19:22:27.577 GCD[11557:1897538] syncConcurrent---begin
2016-09-03 19:22:27.578 GCD[11557:1897538] 1------<NSThread: 0x7f82a1d058b0>{number = 1, name = main}
2016-09-03 19:22:27.578 GCD[11557:1897538] 1------<NSThread: 0x7f82a1d058b0>{number = 1, name = main}
2016-09-03 19:22:27.578 GCD[11557:1897538] 2------<NSThread: 0x7f82a1d058b0>{number = 1, name = main}
2016-09-03 19:22:27.579 GCD[11557:1897538] 2------<NSThread: 0x7f82a1d058b0>{number = 1, name = main}
2016-09-03 19:22:27.579 GCD[11557:1897538] 3------<NSThread: 0x7f82a1d058b0>{number = 1, name = main}
2016-09-03 19:22:27.579 GCD[11557:1897538] 3------<NSThread: 0x7f82a1d058b0>{number = 1, name = main}
2016-09-03 19:22:27.579 GCD[11557:1897538] syncConcurrent---end

  • 並行隊列 + 同步執行中可以看到,所有任務都是在主線程中執行的。由於只有一個線程,所以任務只能一個一個執行。
  • 同時我們還可以看到,所有任務都在打印的syncConcurrent---beginsyncConcurrent---end之間,這說明任務是添加到隊列中馬上執行的。

2. 並行隊列 + 異步執行

  • 可同時開啓多線程,任務交替執行
- (void) asyncConcurrent
{
    NSLog(@"asyncConcurrent---begin");

    dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });

    NSLog(@"asyncConcurrent---end");
}

輸出結果:
2016-09-03 19:27:31.503 GCD[11595:1901548] asyncConcurrent---begin
2016-09-03 19:27:31.504 GCD[11595:1901548] asyncConcurrent---end
2016-09-03 19:27:31.504 GCD[11595:1901626] 1------<NSThread: 0x7f8309c22080>{number = 2, name = (null)}
2016-09-03 19:27:31.504 GCD[11595:1901625] 2------<NSThread: 0x7f8309f0b790>{number = 4, name = (null)}
2016-09-03 19:27:31.504 GCD[11595:1901855] 3------<NSThread: 0x7f8309e1a950>{number = 3, name = (null)}
2016-09-03 19:27:31.504 GCD[11595:1901626] 1------<NSThread: 0x7f8309c22080>{number = 2, name = (null)}
2016-09-03 19:27:31.504 GCD[11595:1901625] 2------<NSThread: 0x7f8309f0b790>{number = 4, name = (null)}
2016-09-03 19:27:31.505 GCD[11595:1901855] 3------<NSThread: 0x7f8309e1a950>{number = 3, name = (null)}

  • 並行隊列 + 異步執行中可以看出,除了主線程,又開啓了3個線程,並且任務是交替着同時執行的。
  • 另一方面可以看出,所有任務是在打印的syncConcurrent---beginsyncConcurrent---end之後纔開始執行的。說明任務不是馬上執行,而是將所有任務添加到隊列之後纔開始異步執行。

接下來再來講講串行隊列的執行方法。

3. 串行隊列 + 同步執行

  • 不會開啓新線程,在當前線程執行任務。任務是串行的,執行完一個任務,再執行下一個任務
- (void) syncSerial
{
    NSLog(@"syncSerial---begin");

    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);

    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });    
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });

    NSLog(@"syncSerial---end");
}

輸出結果爲:
2016-09-03 19:29:00.066 GCD[11622:1903904] syncSerial---begin
2016-09-03 19:29:00.067 GCD[11622:1903904] 1------<NSThread: 0x7fa2e9f00980>{number = 1, name = main}
2016-09-03 19:29:00.067 GCD[11622:1903904] 1------<NSThread: 0x7fa2e9f00980>{number = 1, name = main}
2016-09-03 19:29:00.067 GCD[11622:1903904] 2------<NSThread: 0x7fa2e9f00980>{number = 1, name = main}
2016-09-03 19:29:00.067 GCD[11622:1903904] 2------<NSThread: 0x7fa2e9f00980>{number = 1, name = main}
2016-09-03 19:29:00.067 GCD[11622:1903904] 3------<NSThread: 0x7fa2e9f00980>{number = 1, name = main}
2016-09-03 19:29:00.068 GCD[11622:1903904] 3------<NSThread: 0x7fa2e9f00980>{number = 1, name = main}
2016-09-03 19:29:00.068 GCD[11622:1903904] syncSerial---end

  • 串行隊列 + 同步執行可以看到,所有任務都是在主線程中執行的,並沒有開啓新的線程。而且由於串行隊列,所以按順序一個一個執行。
  • 同時我們還可以看到,所有任務都在打印的syncConcurrent---beginsyncConcurrent---end之間,這說明任務是添加到隊列中馬上執行的。

4. 串行隊列 + 異步執行

  • 會開啓新線程,但是因爲任務是串行的,執行完一個任務,再執行下一個任務
- (void) asyncSerial
{
    NSLog(@"asyncSerial---begin");

    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);

    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });

    NSLog(@"asyncSerial---end");
}

輸出結果爲:
2016-09-03 19:30:08.363 GCD[11648:1905817] asyncSerial---begin
2016-09-03 19:30:08.364 GCD[11648:1905817] asyncSerial---end
2016-09-03 19:30:08.364 GCD[11648:1905895] 1------<NSThread: 0x7fb548c0e390>{number = 2, name = (null)}
2016-09-03 19:30:08.364 GCD[11648:1905895] 1------<NSThread: 0x7fb548c0e390>{number = 2, name = (null)}
2016-09-03 19:30:08.364 GCD[11648:1905895] 2------<NSThread: 0x7fb548c0e390>{number = 2, name = (null)}
2016-09-03 19:30:08.364 GCD[11648:1905895] 2------<NSThread: 0x7fb548c0e390>{number = 2, name = (null)}
2016-09-03 19:30:08.365 GCD[11648:1905895] 3------<NSThread: 0x7fb548c0e390>{number = 2, name = (null)}
2016-09-03 19:30:08.365 GCD[11648:1905895] 3------<NSThread: 0x7fb548c0e390>{number = 2, name = (null)}

  • 串行隊列 + 異步執行可以看到,開啓了一條新線程,但是任務還是串行,所以任務是一個一個執行。
  • 另一方面可以看出,所有任務是在打印的syncConcurrent---beginsyncConcurrent---end之後纔開始執行的。說明任務不是馬上執行,而是將所有任務添加到隊列之後纔開始同步執行。

下邊講講剛纔我們提到過的特殊隊列——主隊列

  • 主隊列:GCD自帶的一種特殊的串行隊列
    • 所有放在主隊列中的任務,都會放到主線程中執行
    • 可使用dispatch_get_main_queue()獲得主隊列

我們再來看看主隊列的兩種組合方式。

5. 主隊列 + 同步執行

  • 互等卡住不可行(在主線程中調用)
- (void)syncMain
{
    NSLog(@"syncMain---begin");

    dispatch_queue_t queue = dispatch_get_main_queue();

    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });   

    NSLog(@"syncMain---end");
}

輸出結果
2016-09-03 19:32:15.356 GCD[11670:1908306] syncMain---begin

這時候,我們驚奇的發現,在主線程中使用主隊列 + 同步執行,任務不再執行了,而且syncMain---end也沒有打印。這是爲什麼呢?

這是因爲我們在主線程中執行這段代碼。我們把任務放到了主隊列中,也就是放到了主線程的隊列中。而同步執行有個特點,就是對於任務是立馬執行的。那麼當我們把第一個任務放進主隊列中,它就會立馬執行。但是主線程現在正在處理syncMain方法,所以任務需要等syncMain執行完才能執行。而syncMain執行到第一個任務的時候,又要等第一個任務執行完才能往下執行第二個和第三個任務。

那麼,現在的情況就是syncMain方法和第一個任務都在等對方執行完畢。這樣大家互相等待,所以就卡住了,所以我們的任務執行不了,而且syncMain---end也沒有打印。

要是如果不再主線程中調用,而在其他線程中調用會如何呢?

  • 不會開啓新線程,執行完一個任務,再執行下一個任務(在其他線程中調用)
dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    [self syncMain];
});

輸出結果:
2016-09-03 19:32:45.496 GCD[11686:1909617] syncMain---begin
2016-09-03 19:32:45.497 GCD[11686:1909374] 1------<NSThread: 0x7faef2f01600>{number = 1, name = main}
2016-09-03 19:32:45.498 GCD[11686:1909374] 1------<NSThread: 0x7faef2f01600>{number = 1, name = main}
2016-09-03 19:32:45.498 GCD[11686:1909374] 2------<NSThread: 0x7faef2f01600>{number = 1, name = main}
2016-09-03 19:32:45.498 GCD[11686:1909374] 2------<NSThread: 0x7faef2f01600>{number = 1, name = main}
2016-09-03 19:32:45.499 GCD[11686:1909374] 3------<NSThread: 0x7faef2f01600>{number = 1, name = main}
2016-09-03 19:32:45.499 GCD[11686:1909374] 3------<NSThread: 0x7faef2f01600>{number = 1, name = main}
2016-09-03 19:32:45.499 GCD[11686:1909617] syncMain---end

  • 在其他線程中使用主隊列 + 同步執行可看到:所有任務都是在主線程中執行的,並沒有開啓新的線程。而且由於主隊列是串行隊列,所以按順序一個一個執行。
  • 同時我們還可以看到,所有任務都在打印的syncConcurrent---begin和syncConcurrent---end之間,這說明任務是添加到隊列中馬上執行的。

6. 主隊列 + 異步執行

  • 只在主線程中執行任務,執行完一個任務,再執行下一個任務
- (void)asyncMain
{
    NSLog(@"asyncMain---begin");

    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });  

    NSLog(@"asyncMain---end");
}

輸出結果:
2016-09-03 19:33:54.995 GCD[11706:1911313] asyncMain---begin
2016-09-03 19:33:54.996 GCD[11706:1911313] asyncMain---end
2016-09-03 19:33:54.996 GCD[11706:1911313] 1------<NSThread: 0x7fb623d015e0>{number = 1, name = main}
2016-09-03 19:33:54.997 GCD[11706:1911313] 1------<NSThread: 0x7fb623d015e0>{number = 1, name = main}
2016-09-03 19:33:54.997 GCD[11706:1911313] 2------<NSThread: 0x7fb623d015e0>{number = 1, name = main}
2016-09-03 19:33:54.997 GCD[11706:1911313] 2------<NSThread: 0x7fb623d015e0>{number = 1, name = main}
2016-09-03 19:33:54.997 GCD[11706:1911313] 3------<NSThread: 0x7fb623d015e0>{number = 1, name = main}
2016-09-03 19:33:54.997 GCD[11706:1911313] 3------<NSThread: 0x7fb623d015e0>{number = 1, name = main}

  • 我們發現所有任務都在主線程中,雖然是異步執行,具備開啓線程的能力,但因爲是主隊列,所以所有任務都在主線程中,並且一個接一個執行。
  • 另一方面可以看出,所有任務是在打印的syncConcurrent---beginsyncConcurrent---end之後纔開始執行的。說明任務不是馬上執行,而是將所有任務添加到隊列之後纔開始同步執行。

弄懂了難理解、繞來繞去的隊列+任務之後,我們來學習一個簡單的東西——GCD線程之間的通訊。

5. GCD線程之間的通訊

在iOS開發過程中,我們一般在主線程裏邊進行UI刷新,例如:點擊、滾動、拖拽等事件。我們通常把一些耗時的操作放在其他線程,比如說圖片下載、文件上傳等耗時操作。而當我們有時候在其他線程完成了耗時操作時,需要回到主線程,那麼就用到了線程之間的通訊。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    for (int i = 0; i < 2; ++i) {
        NSLog(@"1------%@",[NSThread currentThread]);
    }

    // 回到主線程
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"2-------%@",[NSThread currentThread]);
    });
});

輸出結果:
2016-09-03 19:34:59.165 GCD[11728:1913039] 1------<NSThread: 0x7f8319c06820>{number = 2, name = (null)}
2016-09-03 19:34:59.166 GCD[11728:1913039] 1------<NSThread: 0x7f8319c06820>{number = 2, name = (null)}
2016-09-03 19:34:59.166 GCD[11728:1912961] 2-------<NSThread: 0x7f8319e00560>{number = 1, name = main}

  • 可以看到在其他線程中先執行操作,執行完了之後回到主線程執行主線程的相應操作。

6. GCD的其他方法

1. GCD的柵欄方法 dispatch_barrier_async

  • 我們有時需要異步執行兩組操作,而且第一組操作執行完之後,才能開始執行第二組操作。這樣我們就需要一個相當於柵欄一樣的一個方法將兩組異步執行的操作組給分割起來,當然這裏的操作組裏可以包含一個或多個任務。這就需要用到dispatch_barrier_async方法在兩個操作組間形成柵欄。

- (void)barrier
{
    dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"----1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----2-----%@", [NSThread currentThread]);
    });

    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"----3-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----4-----%@", [NSThread currentThread]);
    });
}

輸出結果:
2016-09-03 19:35:51.271 GCD[11750:1914724] ----1-----<NSThread: 0x7fb1826047b0>{number = 2, name = (null)}
2016-09-03 19:35:51.272 GCD[11750:1914722] ----2-----<NSThread: 0x7fb182423fd0>{number = 3, name = (null)}
2016-09-03 19:35:51.272 GCD[11750:1914722] ----barrier-----<NSThread: 0x7fb182423fd0>{number = 3, name = (null)}
2016-09-03 19:35:51.273 GCD[11750:1914722] ----3-----<NSThread: 0x7fb182423fd0>{number = 3, name = (null)}
2016-09-03 19:35:51.273 GCD[11750:1914724] ----4-----<NSThread: 0x7fb1826047b0>{number = 2, name = (null)}

  • 可以看出在執行完柵欄前面的操作之後,才執行柵欄操作,最後再執行柵欄後邊的操作。

2. GCD的延時執行方法 dispatch_after

  • 當我們需要延遲執行一段代碼時,就需要用到GCD的dispatch_after方法。

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 2秒後異步執行這裏的代碼...
   NSLog(@"run-----");
});

3. GCD的一次性代碼(只執行一次) dispatch_once

  • 我們在創建單例、或者有整個程序運行過程中只執行一次的代碼時,我們就用到了GCD的dispatch_once方法。使用dispatch_once函數能保證某段代碼在程序運行過程中只被執行1次。

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只執行1次的代碼(這裏面默認是線程安全的)
});

4. GCD的快速迭代方法 dispatch_apply

  • 通常我們會用for循環遍歷,但是GCD給我們提供了快速迭代的方法dispatch_apply,使我們可以同時遍歷。比如說遍歷0~5這6個數字,for循環的做法是每次取出一個元素,逐個遍歷。dispatch_apply可以同時遍歷多個數字。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(6, queue, ^(size_t index) {
    NSLog(@"%zd------%@",index, [NSThread currentThread]);
});

輸出結果:
2016-09-03 19:37:02.250 GCD[11764:1915764] 1------<NSThread: 0x7fac9a7029e0>{number = 1, name = main}
2016-09-03 19:37:02.250 GCD[11764:1915885] 0------<NSThread: 0x7fac9a614bd0>{number = 2, name = (null)}
2016-09-03 19:37:02.250 GCD[11764:1915886] 2------<NSThread: 0x7fac9a542b20>{number = 3, name = (null)}
2016-09-03 19:37:02.251 GCD[11764:1915764] 4------<NSThread: 0x7fac9a7029e0>{number = 1, name = main}
2016-09-03 19:37:02.250 GCD[11764:1915884] 3------<NSThread: 0x7fac9a76ca10>{number = 4, name = (null)}
2016-09-03 19:37:02.251 GCD[11764:1915885] 5------<NSThread: 0x7fac9a614bd0>{number = 2, name = (null)}

從輸出結果中前邊的時間中可以看出,幾乎是同時遍歷的。

5. GCD的隊列組 dispatch_group

  • 有時候我們會有這樣的需求:分別異步執行2個耗時操作,然後當2個耗時操作都執行完畢後再回到主線程執行操作。這時候我們可以用到GCD的隊列組。
    • 我們可以先把任務放到隊列中,然後將隊列放入隊列組中。
    • 調用隊列組的dispatch_group_notify回到主線程執行操作。

dispatch_group_t group =  dispatch_group_create();

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

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

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



鏈接:http://www.jianshu.com/p/2d57c72016c6
來源:簡書

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章