GCD

1> 概述數據庫

  • Grand Central Dispatch (GCD)是Apple開發的一種多核編程技術。主要用於優化應用程序以支持多核處理器以及其餘對稱多處理系統。編程

  • GCD提供函數實現多線程開發,性能更高,功能也更增強大。安全

  • 它首次發佈在Mac OS X 10.6 ,iOS 4及以上也可用。多線程

 2> 核心概念併發

  • 任務:具備必定功能的代碼段。通常是一個block或者函數app

  • 分發隊列:GCD以隊列的方式進行工做,FIFO異步

  • GCD會根據分發隊列的類型,建立合適數量的線程執行隊列中的任務async

 3> GCD中的隊列函數

  • 串行隊列(SerialQueue):一次只執行一個任務。Serial queue一般用於同步訪問特定的資源或數據。當你建立多個Serial queue時,雖然它們各自是同步執行的,但Serial queue與Serial queue之間是併發執行的。SerialQueue能實現線程同步性能

  • 並行隊列(Concurrent):能夠併發地執行多個任務,雖然遵照FIFO(先進先出),但因爲各個任務被分配到不一樣的線程執行,所以其完成時間有可能不一樣,即:後分配的任務有可能先執行完成;併發隊列必定須要和異步執行的任務(使用dispatch_async())結合起來使用纔有意義。

  • 主隊列:主隊列也是一個串行隊列,主隊列中的任務都在主線程中執行。

 4> 串行隊列(SerialQueue)

  • 第一種:系統提供的建立串行隊列的方法,實際上主隊列的建立方法
1 // 第一種獲取方式:裏面的任務是在主線程依次去執行,dispatch_get_main_queue()獲取主隊列
2 dispatch_queue_t queue = dispatch_get_main_queue();
3 // 往隊列裏面添加任務
4 dispatch_async(queue, ^{
5 NSLog(@"這是第一個任務,當前線程是:%@, 是否主線程 :%d ", [NSThread currentThread],  [[NSThread currentThread] isMainThread]);
6 });
  • 第二種:本身建立的隊列
複製代碼
1 // 參數1:隊列的名字(蘋果推薦使用反向域名去命名)
2     // 參數2:隊列的類型(串行隊列、並行隊列),這種方式建立的隊列,它會本身去開闢一個子線程去完成隊列裏面的任務
3     dispatch_queue_t queue = dispatch_queue_create("com.zf.mySerialQueue", DISPATCH_QUEUE_SERIAL);
4 
5     dispatch_async(queue, ^{
6 NSLog(@"這是第一個任務,當前線程是:%@, 是否主線程 :%d ", [NSThread currentThread],  [[NSThread currentThread] isMainThread]);
7  });
複製代碼

5> 並行隊列

  • 第一種:系統提供的建立並行隊列的方法
複製代碼
1 // 參數1:優先級PRIORITY(有四個,沒有明顯的區別)
2     // 參數2:系統保留字,蘋果預留的參數爲了之後去使用,目前沒有用到,填寫0
3     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
4 
5     dispatch_async(oneQueue, ^{
6  NSLog(@"這是第一個任務。。。線程是:%@, 是否主線程:%d", [NSThread currentThread], [[NSThread currentThread] isMainThread]);
7  });
複製代碼
  • 第二種:本身建立的隊列

  使用的方法同串行隊列,只有建立函數參數2給定隊列的類型的時候,將DISPATCH_QUEUE_SERIAL替換爲DISPATCH_QUEUE_CONCURRENT

複製代碼
1 // 參數1:隊列的名字(蘋果推薦使用反向域名去命名)
2     // 參數2:隊列的類型(串行隊列、並行隊列),這種方式建立的隊列,它會本身去開闢一個子線程去完成隊列裏面的任務
3     dispatch_queue_t queue = dispatch_queue_create("com.zf.mySerialQueue", DISPATCH_QUEUE_CONCURRENT);
4 
5     dispatch_async(queue, ^{
6 NSLog(@"這是第一個任務,當前線程是:%@, 是否主線程 :%d ", [NSThread currentThread],  [[NSThread currentThread] isMainThread]);
7  });
複製代碼

6> GCD功能函數

  • dispatch_async(dispatch_queue_t queue, ^(void)block)    // 異步任務,往隊列中添加任務,任務會排隊執行

  參數1(dispatch_queue_t queue):添加任務的隊列

  參數2(^(void)block):Block,主要是在添加過程當中進行一些操做,操做代碼就寫在Block中

  • dispatch_after()      //往隊列中添加任務,任務不但會排隊,還會在延遲的時間點執行
複製代碼
 1 /*
 2      函數
 3      dispatch_after(dispatch_time_t when, dispatch_queue_t queue, ^(void)block);
 4      
 5      // 系統封裝的代碼快(通常使用)
 6      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(具體的浮點型數字 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 7        延遲執行的內容
 8      });
 9      
10      */
11     // 參數1:延遲的時間,使用dispatch_time()初始化
12     // 參數2:隊列
13     // 參數3:Block
14     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
15         NSLog(@"3.0秒後");
16     });
複製代碼

  dispatch_time(dispatch_time_t when, int64_t delta)對延遲時間進行初始化

  參數1:爲起始時間,系統宏定義,通常使用 DISPATCH_TIME_NOW

  參數2:爲延遲的具體時間類型爲 int64_t,變量的類型爲:具體浮點型數字 * 時間單位(系統的宏定義,能夠根據實際狀況選用)

  • dispatch_apply()    //往隊列中添加任務,任務會重複執行n次
複製代碼
 1 /*
 2      dispatch_apply(size_t iterations, dispatch_queue_t queue, ^(size_t) {
 3         code
 4      });
 5      */
 6     dispatch_queue_t queue = dispatch_queue_create("com.zf.myQueue", DISPATCH_QUEUE_CONCURRENT);
 7     // 參數1:添加任務的個數
 8     // 參數2:隊列
 9     // 參數3:Block,這個Block沒有變量名,須要本身添加
10     dispatch_apply(10, queue, ^(size_t index) {
11         NSLog(@"%zu", index);
12     });
複製代碼

:函數dispatch_apply()的參數3Block沒有變量名,須要本身添加

  • dispatch_group_async()   //將任務添加到隊列中,並添加分組標記

  • dispatch_group_notify()    //將任務添加到隊列中,當某個分組的全部任務執行完以後,此任務纔會執行

  • 複製代碼
     1 //    dispatch_group_t主要用於把一些不相關的任務歸爲一組
     2 //    組裏面放的是隊列
     3 //    dispatch_group_async做用是往組裏面的隊列添加任務
     4 //    dispatch_group_notify做用:監聽組裏面的任務,等到組裏面的任務所有執行完成以後,纔會執行它裏面的任務
     5 
     6     //一、建立隊列
     7     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
     8     //二、建立組
     9     dispatch_group_t group = dispatch_group_create();
    10          // 三、往組裏面的隊列添加任務(注意:在執行notify以前最起碼要向隊列中放置一個任務才能夠,不然,notify裏面的任務不會等待小組裏面的其餘任務執行完才執行。)
    11     dispatch_group_async(group, queue, ^{
    12          NSLog(@"這是第一個任務。。。線程是:%@, 是否主線程:%d", [NSThread currentThread], [[NSThread currentThread] isMainThread]);
    13     });
    14    
    15    dispatch_group_notify(group, queue, ^{
    16         NSLog(@"我是最後一個任務,組裏面的其餘任務都執行完畢以後,我就會執行");
    17     });
    複製代碼
  • dispatch_barrier_async()  //將任務添加到隊列中,此任務執行的時候,其餘任務中止執行
複製代碼
 1 // 數據庫的讀取。。。能夠併發執行,經過 GCD 裏面的並行隊列去實現
 2 // 數據庫的寫入。。。。只能串行執行,經過 GCD 裏面的串行隊列去實現
 3 // 可是真正的項目,確定是既有數據的讀取,也有數據庫的寫入。。。如何解決該問題:dispatch_barrier_async 在它以前的任務能夠併發去執行,在他以後的任務也能夠去併發執行
 4    dispatch_queue_t queue = dispatch_queue_create("concurrentTest",DISPATCH_QUEUE_CONCURRENT);
 5     dispatch_async(queue, ^{
 6 NSLog(@"這是第一個讀取數據的任務。。。線程是:%@, 是否主線程:%d", [NSThread currentThread], [[NSThread currentThread] isMainThread]);
 7     });
 8     
 9     dispatch_barrier_async(queue, ^{
10         NSLog(@"正在在數據庫裏寫東西,不要打擾我");
11     });
12     
13     dispatch_async(queue, ^{
14 NSLog(@"這是第二個讀取數據的任務。。。線程是:%@, 是否主線程:%d", [NSThread currentThread], [[NSThread currentThread] isMainThread]);
15     });
複製代碼
  • dispatch_once()   //任務添加到隊列中,但任務在程序運行過程當中,只執行一次

  dispatch_once: 該函數接收一個dispatch_once用於檢查該代碼塊是否已經被調度的謂詞(是一個長整型,實際上做爲BOOL使用)。它還接收一個但願在應用的生命週期內僅被調度一次的代碼塊。

  dispatch_once 不只意味着代碼僅會被運行一次,並且仍是線程安全的,這就意味着你不須要使用諸如@synchronized之類的來防止使用多個線程或者隊列時不一樣步的問題。

  運用代碼(單例的完整定義)

複製代碼
 1 static MyHandle *handle = nil;
 2 
 3 + (MyHandle *)sharedMyHandle
 4 {    
 5     // 在GCD中只執行一次,用於記錄內容是否執行過
 6     static dispatch_once_t onceToken;
 7     
 8     dispatch_once(&onceToken, ^{
 9         handle = [MyHandle new];
10     });
11     
12     return handle;
13 }
複製代碼
  • dispatch_sync()   //同步任務 將任務添加到隊列中,block不執行完,下面代碼不會執行

  與 dispatch_async() 的區別:

   dispatch_async() 不等 block 體執行完,就去執行下面的代碼,會在另外的線程中執行

   dispatch_sync() 會等待 block 體執行完成以後,纔會去執行 block 體外面的代碼,會在當前的線程中執行,當前線程有多是主線程,也有多是子線程

  • dispatch_async_f()  //將任務添加到隊列中,任務是函數非block
複製代碼
 1 // 函數
 2 void function(void * str){
 3     NSLog(@"這是一個函數,%s",str);
 4 }
 5 
 6 // 第一個參數:隊列
 7 // 第二個參數:函數參數的內容
 8 // 第三個參數:函數
 9 dispatch_queue_t queue  = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
10 dispatch_async_f(queue, @"passValue", function);
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息