天天看點

GCD的定義及使用詳解(同步異步、并發串行、線程間通信、延時執行、隻執行一次代碼)

GCD

1、Grand Central Dispatch是由蘋果開發的一個多核程式設計的解決方案,自動管理現成的生命周期(建立線程、排程任務、銷毀線程)。

2、主要包括任務(執行什麼操作)和隊列(用來存放任務)。

3、同步方式(目前線程)

     異步方式(開一條線程)

4、并發隊列:可以讓多個任務同時執行,隻有在異步方式下才有效

     串行隊列:任務一個接一個執行

總結:同步異步決定能不能開啟線程,并發串行決定是多個任務同時執行還是一個一個執行

5、GCD中有三種隊列類型:

  1. The main queue: 與主線程功能相同。實際上,送出至main queue的任務會在主線程中執行。main queue可以調用dispatch_get_main_queue()來獲得。因為main queue是與主線程相關的,是以這是一個串行隊列。
  2. Global queues: 全局隊列是并發隊列,并由整個程序共享。程序中存在三個全局隊列:高、中(預設)、低三個優先級隊列。可以調用dispatch_get_global_queue函數傳入優先級來通路隊列。
  3. 使用者隊列: 使用者隊列 (GCD并不這樣稱呼這種隊列, 但是沒有一個特定的名字來形容這種隊列,是以我們稱其為使用者隊列) 是用函數 

    dispatch_queue_create

     建立的隊列. 這些隊列是串行的。

6、隊列的使用

    1.全局并行隊列異步執行

/**
 *  async -- 并發隊列(最常用)
 *  會不會建立線程:會,一般同時開多條
 *  任務的執行方式:并發執行
 */
- (void)asyncGlobalQueue
{
    // 獲得全局的并發隊列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 将 任務 添加 全局隊列 中去 異步 執行
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔3---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔4---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔5---%@", [NSThread currentThread]);
    });
}
           

     2.串行隊列異步執行

/**
 *  async -- 串行隊列(有時候用)
 *  會不會建立線程:會,一般隻開1條線程
 *  任務的執行方式:串行執行(一個任務執行完畢後再執行下一個任務)
 */
- (void)asyncSerialQueue
{
    // 1.建立一個串行隊列
    dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue", NULL);
    
    // 2.将任務添加到串行隊列中 異步 執行
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔3---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔4---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔5---%@", [NSThread currentThread]);
    });
    
    // 3.非ARC,需要釋放建立的隊列
//    dispatch_release(queue);
}
           

      3.主隊列異步執行

/**
 *  async -- 主隊列(很常用)
 */
- (void)asyncMainQueue
{
    // 1.主隊列(添加到主隊列中的任務,都會自動放到主線程中去執行)
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 2.添加 任務 到主隊列中 異步 執行
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔3---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔4---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下載下傳圖檔5---%@", [NSThread currentThread]);
    });
}
           

       4.全局并發隊列同步執行

/**
 *  sync -- 并發隊列
 *  會不會建立線程:不會
 *  任務的執行方式:串行執行(一個任務執行完畢後再執行下一個任務)
 *  并發隊列失去了并發的功能
 */
- (void)syncGlobalQueue
{
    // 獲得全局的并發隊列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 将 任務 添加到 全局并發隊列 中 同步 執行
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔3---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔4---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔5---%@", [NSThread currentThread]);
    });
}
           

        5.串行隊列同步執行

/**
 *  sync -- 串行隊列
 *  會不會建立線程:不會
 *  任務的執行方式:串行執行(一個任務執行完畢後再執行下一個任務)
 */
- (void)syncSerialQueue
{
    // 建立一個串行隊列
    dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue", NULL);
    
    // 将 任務 添加到 串行隊列 中 同步 執行
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔3---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔4---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下載下傳圖檔5---%@", [NSThread currentThread]);
    });
}
           

7、線程間通信(最常用)

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"donwload---%@", [NSThread currentThread]);
        // 1.子線程下載下傳圖檔
        NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        
        // 2.回到主線程設定圖檔
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"setting---%@ %@", [NSThread currentThread], image);
            [self.button setImage:image forState:UIControlStateNormal];
        });
    });
           

8、延遲執行

// 3秒後回到主線程執行block中的代碼
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"------task------%@", [NSThread currentThread]);
    });
           
// 3秒後自動開啟新線程 執行block中的代碼
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"------task------%@", [NSThread currentThread]);
    });
           
// 一旦定制好延遲任務後,不會卡主目前線程
    [self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];
           

9、一次性代碼

static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"----once");
        HMImageDownloader *downloader = [[HMImageDownloader alloc] init];
        [downloader download];
    });
           

繼續閱讀