<!--?xml version="1.0" encoding="UTF-8" standalone="no"?--> 更正:隊列名稱的作用的圖中,箭頭標註的有些問題,已修正 1.0 GCD簡介 GCD概念 :(Grand Central Dispatch)可譯為“偉大的中樞調度器” 純C語言,提供 ...
更正:隊列名稱的作用的圖中,箭頭標註的有些問題,已修正 1.0 GCD簡介 GCD概念 :(Grand Central Dispatch)可譯為“偉大的中樞調度器”
- 純C語言,提供了非常多強大的函數
GCD 的優勢:
- GCD是蘋果公司為多核的並行運算提出的解決方案
- GCD會自動利用更多的CPU內核(比如雙核、四核)
- GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程)
- 程式員只需要告訴GCD想要執行什麼任務,不需要編寫任何線程管理代碼
GCD的兩個核心概念: 1) 任務:執行什麼操作 2) 隊列:用來存放任務 註意: (1)GCD存在於 libdispatch 這個庫中,這個調度庫包含了GCD的所有的東西,但任何IOS程式,預設就載入了這個庫,在程式運行的過程中會動態的載入這個庫,不需要我們手動導入。 (2)GCD是純C語言的,因此我們在編寫GCD相關代碼的時候,面對的函數,而不是方法。 (3)GCD中的函數大多數都以dispatch開頭。 2.0 GCD的使用 GCD的使用步驟: 步驟1 : 創建隊列 步驟2 : 創建任務
- 確定想做的事情
- GCD會自動將隊列中的任務取出,放到對應的線程中執行
- 任務的取出遵循隊列的FIFO原則:先進先出,後進後出
- 同步
- 非同步
1 (1)任務的執行:同步 2 3 //queue:隊列 block:任務 4 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); 5 6 (2)任務的執行:非同步 7 8 - 函數1 9 10 //queue:隊列 block:任務 11 dispatch_async(dispatch_queue_t queue, dispatch_block_t block); 12 13 - 函數2 14 15 // 在前面的任務執行結束後它才執行,而且它後面的任務等它執行完成之後才會執行 16 dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);【區別】同步 & 非同步:同步和非同步決定了要不要開啟新的線程
- 同步:只能在當前線程中執行任務,不具備開啟新線程的能力
- 非同步:可以在新的線程中執行任務,具備開啟新線程的能力
- 併發:允許多個任務併發(同時)執行
- 串列:一個任務執行完畢後,再執行下一個任務
2.2 GCD的使用 - 隊列 隊列分類: (1)併發隊列(Concurrent Dispatch Queue)
- 可以讓多個任務併發(同時)執行(自動開啟多個線程同時執行任務)
- 併發功能只有在非同步(dispatch_async)函數下才有效
- 讓任務一個接著一個地執行(一個任務執行完畢後,再執行下一個任務)
- 凡是函數名種帶有create\copy\new\retain等字眼, 都應該在不需要使用這個數據的時候進行release
- GCD的數據類型在ARC環境下不需要再做release dispatch_release(queue); // 非ARC需要釋放手動創建的隊列
- CF(Core Foundation)的數據類型在ARC環境下還是需要再做release
(1)如果非同步任務前面有同步任務 就會先執行同步任務同步任務是按順序執行的任務等他執行完了才會執行並行中的非同步任務 (可以做到阻塞 控制任務的執行順序) |
(2)如果非同步任務後面有同步任務 兩個任務會並行(同時)執行 |
1 方式1 - 手動創建併發隊列: 2 3 dispatch_queue_create( 4 constchar *label, // 隊列名稱 5 dispatch_queue_attr_t attr // 隊列的類型 6 ); 7 8 // 1.創建併發隊列 DISPATCH_QUEUE_CONCURRENT (併發) 9 dispatch_queue_t queue = dispatch_queue_create(“TD", DISPATCH_QUEUE_CONCURRENT); 10 11 // 2.非ARC需要釋放手動創建的隊列 12 dispatch_release(queue); 13 14 方式2 - 獲取全局併發隊列:(GCD預設已經提供了全局的併發隊列,供整個應用使用,可以無需手動創建) 15 16 Xcode 7.2定義方式: 17 dispatch_get_global_queue( 18 long identifier, // 隊列的優先順序 19 unsignedlong flags // 此參數暫時無用,用0即可 20 ); 21 22 全局併發隊列的優先順序:(級別由高到低) 23 24 #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高 25 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 預設(中) 26 #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低 27 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 後臺 28 29 // 獲取全局併發隊列 30 dispatch_queue_t queue = 31 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2.2.1【代碼】同步 + 併發 在實際開發中,同步任務可以保證執行完成之後,才讓後續的非同步任務開始執行,用於控制任務之間的先後順序,在後臺線程中,處理“用戶登錄”
1 #import "ViewController.h" 2 3 @interface ViewController () 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 // Do any additional setup after loading the view, typically from a nib. 12 } 13 14 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 15 [self syncConcurrent]; 16 } 17 18 #pragma mark - 同步函數 + 併發隊列:不會開啟新的線程,在當前線程執行任務(主線程),順序執行,併發隊列失去了併發的功能 19 - (void)syncConcurrent { 20 NSLog(@"同步併發 ----- begin"); 21 22 // 1.獲得全局的併發隊列 23 dispatch_queue_t queue = 24 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 25 26 // 2.將任務加入隊列 27 dispatch_sync(queue, ^{ 28 NSLog(@"1-----%@", [NSThread currentThread]); 29 }); 30 dispatch_sync(queue, ^{ 31 NSLog(@"2-----%@", [NSThread currentThread]); 32 }); 33 dispatch_sync(queue, ^{ 34 NSLog(@"3-----%@", [NSThread currentThread]); 35 }); 36 37 NSLog(@"同步併發 ----- end"); 38 } 39 40 #pragma mark - 寫法2 41 - (void)concurrentSync { 42 // 1. 創建併發隊列 43 dispatch_queue_t conCurrentQueue = 44 dispatch_queue_create("TD", DISPATCH_QUEUE_CONCURRENT); 45 46 // 2. 創建任務 47 void (^task1)() = ^() { 48 NSLog(@"---task1---%@", [NSThread currentThread]); 49 }; 50 51 void (^task2)() = ^() { 52 NSLog(@"---task2---%@", [NSThread currentThread]); 53 }; 54 55 void (^task3)() = ^() { 56 NSLog(@"---task3---%@", [NSThread currentThread]); 57 }; 58 59 // 3. 將同步任務添加到併發隊列中 60 dispatch_sync(conCurrentQueue, task1); 61 dispatch_sync(conCurrentQueue, task2); 62 dispatch_sync(conCurrentQueue, task3); 63 } 64 65 - (void)didReceiveMemoryWarning { 66 [super didReceiveMemoryWarning]; 67 // Dispose of any resources that can be recreated. 68 } 69 70 @end 71 72 列印結果: 73 74 2016-03-20 00:04:08.387 同步併發[1702:246074] 同步併發 ----- begin 75 2016-03-20 00:04:08.387 同步併發[1702:246074] 1-----<NSThread: 0x7fe963d07360>{number = 1, name = main} 76 2016-03-20 00:04:08.387 同步併發[1702:246074] 2-----<NSThread: 0x7fe963d07360>{number = 1, name = main} 77 2016-03-20 00:04:08.388 同步併發[1702:246074] 3-----<NSThread: 0x7fe963d07360>{number = 1, name = main} 78 2016-03-20 00:04:08.388 同步併發[1702:246074] 同步併發 ----- end 79 80 2016-03-20 00:05:07.968 同步併發[1724:247291] ---task1---<NSThread: 0x7f8e71400d20>{number = 1, name = main} 81 2016-03-20 00:05:07.969 同步併發[1724:247291] ---task2---<NSThread: 0x7f8e71400d20>{number = 1, name = main} 82 2016-03-20 00:05:07.969 同步併發[1724:247291] ---task3---<NSThread: 0x7f8e71400d20>{number = 1, name = main}View Code
2.2.1【代碼】非同步 + 併發
1 #import "ViewController.h" 2 3 @interface ViewController () 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 // Do any additional setup after loading the view, typically from a nib. 12 } 13 14 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 15 [self asyncConcurrent]; 16 } 17 18 #pragma mark - 非同步函數 + 併發隊列:可以同時開啟多條線程,在當前線程執行任務(主線程),無序執行(按照任務添加到隊列中的順序被調度),線程條數具體由`可調度線程池/底層線程池`來決定 19 - (void)asyncConcurrent { 20 NSLog(@"非同步併發 ----- begin"); 21 22 // 1.獲得全局的併發隊列 23 dispatch_queue_t queue = 24 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 25 26 // 2.將任務加入隊列 27 dispatch_sync(queue, ^{ 28 NSLog(@"1-----%@", [NSThread currentThread]); 29 }); 30 dispatch_sync(queue, ^{ 31 NSLog(@"2-----%@", [NSThread currentThread]); 32 }); 33 dispatch_sync(queue, ^{ 34 NSLog(@"3-----%@", [NSThread currentThread]); 35 }); 36 37 NSLog(@"非同步併發 ----- begin"); 38 } 39 40 #pragma mark - 寫法2 41 - (void)concurrentAsync { 42 // 1.創建併發隊列 43 dispatch_queue_t conCurrentQueue = 44 dispatch_queue_create("TD", DISPATCH_QUEUE_CONCURRENT); 45 46 // 2. 創建任務 47 void (^task1)() = ^() { 48 NSLog(@"---task1---%@", [NSThread currentThread]); 49 }; 50 51 void (^task2)() = ^() { 52 NSLog(@"---task2---%@", [NSThread currentThread]); 53 }; 54 55 void (^task3)() = ^() { 56 NSLog(@"---task3---%@", [NSThread currentThread]); 57 }; 58 59 // 3. 將非同步任務添加到併發隊列中 60 dispatch_async(conCurrentQueue, task1); 61 dispatch_async(conCurrentQueue, task2); 62 dispatch_async(conCurrentQueue, task3); 63 } 64 65 - (void)didReceiveMemoryWarning { 66 [super didReceiveMemoryWarning]; 67 // Dispose of any resources that can be recreated. 68 } 69 70 @end 71 72 列印結果: 73 74 2016-03-20 00:11:16.307 非同步併發[1879:254274] 非同步併發 ----- begin 75 2016-03-20 00:11:16.308 非同步併發[1879:254274] 1-----<NSThread: 0x7fd598d02490>{number = 1, name = main} 76 2016-03-20 00:11:16.308 非同步併發[1879:254274] 2-----<NSThread: 0x7fd598d02490>{number = 1, name = main} 77 2016-03-20 00:11:16.308 非同步併發[1879:254274] 3-----<NSThread: 0x7fd598d02490>{number = 1, name = main} 78 2016-03-20 00:11:16.308 非同步併發[1879:254274] 非同步併發 ----- begin 79 80 2016-03-20 00:18:18.557 非同步併發[1945:260502] ---task2---<NSThread: 0x7fbf68d927b0>{number = 3, name = (null)} 81 2016-03-20 00:18:18.557 非同步併發[1945:260628] ---task3---<NSThread: 0x7fbf68e24570>{number = 4, name = (null)} 82 2016-03-20 00:18:18.557 非同步併發[1945:260503] ---task1---<NSThread: 0x7fbf68f15ae0>{number = 2, name = (null)}View Code
2.2.2 創建隊列 - 串列隊列
1 手動創建串列隊列: 2 3 dispatch_queue_create( 4 constchar *label, // 隊列名稱 5 dispatch_queue_attr_t attr // 隊列的類型 6 ); 7 8 //1.創建串列隊列 9 10 //方式1:DISPATCH_QUEUE_SERIAL (串列) 11 dispatch_queue_t queue = dispatch_queue_create(“TD", DISPATCH_QUEUE_SERIAL); 12 //方式2:傳 NULL 13 dispatch_queue_t queue = dispatch_queue_create(“TD", NULL); 14 15 // 2.非ARC需要釋放手動創建的隊列 16 dispatch_release(queue);
- 串列隊列中的任務都是按順序執行,誰在前就先執行誰
- 主線程和子線程平等,一樣誰在前選執行誰
- 執行完一個才會執行下一個任務
- 串列隊列中的任務都是按順序執行,誰在前就先執行誰
- 主線程和子線程平等,一樣誰在前選執行誰
- 執行完一個才會執行下一個任務
1 #import "ViewController.h" 2 3 @interface ViewController () 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 // Do any additional setup after loading the view, typically from a nib. 12 } 13 14 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 15 [self syncSerial]; 16 } 17 18 #pragma mark - 同步函數 + 串列隊列:不會開啟新的線程,在當前線程執行任務(主線程),任務是串列的(順序執行) 19 - (void)syncSerial { 20 NSLog(@"同步串列 ----- begin"); 21 22 // 1.創建串列隊列 23 dispatch_queue_t queue = dispatch_queue_create("TD", DISPATCH_QUEUE_SERIAL); 24 25 // 2.將任務加入隊列 26 dispatch_sync(queue, ^{ 27 NSLog(@"1-----%@", [NSThread currentThread]); 28 }); 29 dispatch_sync(queue, ^{ 30 NSLog(@"2-----%@", [NSThread currentThread]); 31 }); 32 dispatch_sync(queue, ^{ 33 NSLog(@"3-----%@", [NSThread currentThread]); 34 }); 35 36 NSLog(@"同步串列 ----- end"); 37 } 38 39 #pragma mark - 寫法2 40 - (void)serialSyncDemo { 41 // 1.創建隊列 42 dispatch_queue_t serialQueue = 43 dispatch_queue_create("TD", DISPATCH_QUEUE_SERIAL); 44 45 // 2.創建任務 46 void (^task1)() = ^() { 47 NSLog(@"task1---%@", [NSThread currentThread]); 48 }; 49 50 void (^task2)() = ^() { 51 NSLog(@"task2---%@", [NSThread currentThread]); 52 }; 53 54 void (^task3)() = ^() { 55 NSLog(@"task3---%@", [NSThread currentThread]); 56 }; 57 58 // 3.將同步任務,添加到串列隊列 59 dispatch_sync(serialQueue, task3); 60 dispatch_sync(serialQueue, task1); 61 dispatch_sync(serialQueue, task2); 62 } 63 64 - (void)didReceiveMemoryWarning { 65 [super didReceiveMemoryWarning]; 66 // Dispose of any resources that can be recreated. 67 } 68 69 @end 70 71 列印結果: 72 73 2016-03-20 00:38:13.648 同步串列[2145:276628] 同步串列 ----- begin 74 2016-03-20 00:38:13.649 同步串列[2145:276628] 1-----<NSThread: 0x7fab52f04910>{number = 1, name = main} 75 2016-03-20 00:38:13.649 同步串列[2145:276628] 2-----<NSThread: 0x7fab52f04910>{number = 1, name = main} 76 2016-03-20 00:38:13.649 同步串列[2145:276628] 3-----<NSThread: 0x7fab52f04910>{number = 1, name = main} 77 2016-03-20 00:38:13.649 同步串列[2145:276628] 同步串列 ----- end 78 79 2016-03-20 00:47:53.272 同步串列[2248:284920] task1---<NSThread: 0x7fd910c05150>{number = 1, name = main} 80 2016-03-20 00:47:53.273 同步串列[2248:284920] task2---<NSThread: 0x7fd910c05150>{number = 1, name = main} 81 2016-03-20 00:47:53.273 同步串列[2248:284920] task3---<NSThread: 0x7fd910c05150>{number = 1, name = main}View Code
2.2.2【代碼】非同步 + 串列
- 串列隊列中的任務都是按順序執行,誰在前就先執行誰
- 主線程和子線程平等,一樣誰在前選執行誰
- 執行完一個才會執行下一個任務
串列隊列,非同步任務,在多線程中,是斯坦福大學最推薦的一種多線程方式!
|
1 #import "ViewController.h" 2 3 @interface ViewController () 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 // Do any additional setup after loading the view, typically from a nib. 12 } 13 14 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 15 [self asyncSerial]; 16 } 17 18 #pragma mark - 非同步函數 + 串列隊列:會開啟新的線程,在子線程執行任務,任務是串列的(順序執行),只開一條線程 19 - (void)asyncSerial { 20 NSLog(@"非同步串列 ----- begin"); 21 NSLog(@"主線程 ----- %@", [NSThread mainThread]); 22 23 // 1.創建串列隊列 24 //寫法1: 25 dispatch_queue_t queue = dispatch_queue_create("TD", DISPATCH_QUEUE_SERIAL); 26 //寫法2: 27 dispatch_queue_t queue = dispatch_queue_create("TD", NULL); 28 29 // 2.將任務加入隊列 30 dispatch_async(queue, ^{ 31 NSLog(@"1-----%@", [NSThread currentThread]); 32 }); 33 dispatch_async(queue, ^{ 34 NSLog(@"2-----%@", [NSThread currentThread]); 35 }); 36 dispatch_async(queue, ^{ 37 NSLog(@"3-----%@", [NSThread currentThread]); 38 }); 39 40 NSLog(@"非同步串列 ----- end"); 41 } 42 43 #pragma mark - 寫法2 44 - (void)serialAsyncDemo { 45 // 1.創建隊列 46 dispatch_queue_t serialQueue = 47 dispatch_queue_create("TD", DISPATCH_QUEUE_SERIAL); 48 49 // 2.創建任務 50 void (^task1)() = ^() { 51 NSLog(@"task1---%@", [NSThread currentThread]); 52 }; 53 54 void (^task2)() = ^() { 55 NSLog(@"task2---%@", [NSThread currentThread]); 56 }; 57 58 void (^task3)() = ^() { 59 NSLog(@"task3---%@", [NSThread currentThread]); 60 }; 61 62 // 3.將非同步任務添加到串列隊列<