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功能函數
參數1(dispatch_queue_t queue):添加任務的隊列
參數2(^(void)block):Block,主要是在添加過程當中進行一些操做,操做代碼就寫在Block中
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,變量的類型爲:具體浮點型數字 * 時間單位(系統的宏定義,能夠根據實際狀況選用)
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 });
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用於檢查該代碼塊是否已經被調度的謂詞(是一個長整型,實際上做爲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_async() 的區別:
dispatch_async() 不等 block 體執行完,就去執行下面的代碼,會在另外的線程中執行
dispatch_sync() 會等待 block 體執行完成以後,纔會去執行 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);