線程vs進程
進程: 對于移動端來講一個APP的啟動就相當于手機系統開啟了一個進程,每個程序只能開啟一個進程,也就是說對于手機系統而言都是單進程應用。
線程: 可以理解為獨立執行的代碼段,一個線程同時間只能執行一個任務。
提示: iOS程序啟動之后就創建了一個主線程,用于刷新程序UI,所以才有你看到的絢麗多彩的界面。
同步和異步
線程分同步sync
和異步async
之分
- 同步線程:同步線程會阻塞當前線程去執行線程內的任務,執行完之后才會反回當前線程。
- 異步線程:異步線程不會阻塞當前線程,會開啟其他線程去執行線程內的任務。(推薦使用)
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"異步執行任務,不會阻塞當前線程");
});
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"同步執行任務,注意——>");//這段代碼不會打印,會產生死鎖,因為同步主線程會造成主隊列線程相互等待。
});
隊列
GCD中一個block代碼塊就是一個隊列,隊列可以是并行也可以是串行的。默認情況下,它們是串行的,也就是說,任何給定的時間內,只能有一個單獨的 block 運行。隊列也可以是并行的,也就是同一時間內允許多個 block 一起執行。其實隊列很大程度的幫助我們更方便的使用多線程來調度我們的功能。
主線程隊列
1.獲取主線程串行隊列
dispatch_queue_t mainQueue = dispatch_get_main_queue();//注意:禁止再次隊列中同步執行任務。因為會產生死鎖
2.主線程串行隊列異步執行任務,在主線程運行,不會產生死鎖
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
NSLog(@"主隊列");
});
全局并發隊列
耗時的操作,比如讀取網絡數據,IO,數據庫讀寫等,我們會在另外一個線程中處理這些操作,然后通知主線程更新界面
1.獲取全局并發隊列
//全局并發隊列中 GCD 為我們提供了優先級
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
*/
2.多個線程任務在全局并發隊列中執行
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"current task");
dispatch_async(globalQueue, ^{
NSLog(@"最先加入全局并發隊列");
});
dispatch_async(globalQueue, ^{
NSLog(@"次加入全局并發隊列");
});
NSLog(@"next task");
控制臺輸出:
2015-11-18 16:54:52.202 Whisper[39827:403208] current task
2015-11-18 16:54:52.203 Whisper[39827:403208] next task
2015-11-18 16:54:52.205 Whisper[39827:403309] 最先加入全局并發隊列
2015-11-18 16:54:52.205 Whisper[39827:403291] 次加入全局并發隊列
異步線程的執行順序是不確定的。幾乎同步開始執行
全局并發隊列由系統默認生成的,所以無法調用dispatch_resume()和dispatch_suspend()來控制執行繼續或中斷。
自定義隊列
自定義隊列就是拋開系統為我們創建的全局主隊列以及全局并發隊列,自己創建一個隊列
//自定義串行隊列
dispatch_queue_t serialQueue = dispatch_queue_create("com.custom.serialQueue", DISPATCH_QUEUE_SERIAL);
//自定義并行隊列
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.custom.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_create
后面第一個參數通常用反域名字符表示,你可以作為你識別的唯一名稱,方便調試
有了隊列我們就可以添加任務來執行了
示例:
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"current task");
dispatch_async(conCurrentQueue, ^{
NSLog(@"先加入隊列");
});
dispatch_async(conCurrentQueue, ^{
NSLog(@"次加入隊列");
});
NSLog(@"next task");
控制臺輸出如下:
2015-11-19 10:45:22.290 Whisper[1050:26445] current task
2015-11-19 10:45:22.290 Whisper[1050:26445] next task
2015-11-19 10:45:22.290 Whisper[1050:26505] 次加入隊列
2015-11-19 10:45:22.290 Whisper[1050:26500] 先加入隊列
隊列組
當遇到需要執行多個線程并發執行,然后等多個線程都結束之后,再匯總執行結果時可以用group queue
dispatch_group_t groupQueue = dispatch_group_create();
使用示例:
dispatch_queue_t conCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_group_t groupQueue = dispatch_group_create();
NSLog(@"current task");
dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
NSLog(@"并行任務1");
});
dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
NSLog(@"并行任務2");
});
dispatch_group_notify(groupQueue, mainQueue, ^{
NSLog(@"groupQueue中的任務 都執行完成,回到主線程更新UI");
});
NSLog(@"next task");
控制臺輸出:
2017-08-15 17:42:42.355 TestProject[21907:682737] current task
2017-08-15 17:42:42.356 TestProject[21907:682737] next task
2017-08-15 17:42:42.356 TestProject[21907:682850] 并行任務1
2017-08-15 17:42:42.356 TestProject[21907:682849] 并行任務2
2017-08-15 17:42:42.504 TestProject[21907:682737] groupQueue中的任務 都執行完成,回到主線程更新UI
//可以阻塞當前線程 起到延遲等待效果
dispatch_group_wait(groupQueue, delayTime);
GCD 系統常用的 dispatch
方法
1.dispatch_once 實現單利模式
+ (UIColor *)defaultInstance;
{
static UIColor *color;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
color = [UIColor colorWithRed:0.380f green:0.376f blue:0.376f alpha:1.000f];
});
return color;
}
上面的 block 只會運行一次。并且在連續的調用中,這種檢查是很高效的
2.dispatch_after
被用作延遲添加
dispatch_queue_t mainQueue = dispatch_get_main_queue();
NSLog(@"current task");
dispatch_after(delayTime3, mainQueue, ^{
NSLog(@"3秒之后添加到隊列");
});
dispatch_after(delayTime2, mainQueue, ^{
NSLog(@"2秒之后添加到隊列");
});
NSLog(@"next task");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"延遲兩秒執行");
});
3.dispatch_apply
dispatch_apply函數的功能:把一項任務提交到隊列中多次執行,隊列可以是串行也可以是并行,dispatch_apply不會立刻返回,在執行完block中的任務后才會返回,是同步執行的函數。
dispatch_queue_t seriaQueue = dispatch_queue_create("com.seriaQueue", DISPATCH_QUEUE_SERIAL);
dispatch_apply(3, seriaQueue, ^(size_t index) {
index++;
NSLog(@"index=%zu",index);
});
NSLog(@"執行完成");
控制臺輸出:
//如果 seriaQueue 為并行隊列 index 也可能是無須輸出
2017-08-15 17:56:09.125 TestProject[22222:694749] index=1
2017-08-15 17:56:09.125 TestProject[22222:694749] index=2
2017-08-15 17:56:09.126 TestProject[22222:694749] index=3
2017-08-15 17:56:09.126 TestProject[22222:694749] 執行完成
4.dispatch_barrier_async 柵欄的作用
功能:是在并行隊列中,等待在dispatch_barrier_async之前加入的隊列全部執行完成之后(這些任務是并發執行的)再執行dispatch_barrier_async中的任務,dispatch_barrier_async中的任務執行完成之后,再去執行在dispatch_barrier_async之后加入到隊列中的任務(這些任務是并發執行的)。
示例:
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(conCurrentQueue, ^{
NSLog(@"dispatch 1");
});
dispatch_async(conCurrentQueue, ^{
NSLog(@"dispatch 2");
});
dispatch_barrier_async(conCurrentQueue, ^{
NSLog(@"dispatch barrier");
});
dispatch_async(conCurrentQueue, ^{
NSLog(@"dispatch 3");
});
dispatch_async(conCurrentQueue, ^{
NSLog(@"dispatch 4");
});
控制臺輸出:
2015-11-19 18:12:34.125 Whisper[22633:297257] dispatch 1
2015-11-19 18:12:34.125 Whisper[22633:297258] dispatch 2
2015-11-19 18:12:34.126 Whisper[22633:297258] dispatch barrier
2015-11-19 18:12:34.127 Whisper[22633:297258] dispatch 3
2015-11-19 18:12:34.127 Whisper[22633:297257] dispatch 4