線程vs進(jìn)程
進(jìn)程: 對(duì)于移動(dòng)端來講一個(gè)APP的啟動(dòng)就相當(dāng)于手機(jī)系統(tǒng)開啟了一個(gè)進(jìn)程,每個(gè)程序只能開啟一個(gè)進(jìn)程递礼,也就是說對(duì)于手機(jī)系統(tǒng)而言都是單進(jìn)程應(yīng)用。
線程: 可以理解為獨(dú)立執(zhí)行的代碼段喂饥,一個(gè)線程同時(shí)間只能執(zhí)行一個(gè)任務(wù)亲轨。
提示: iOS程序啟動(dòng)之后就創(chuàng)建了一個(gè)主線程,用于刷新程序UI孩锡,所以才有你看到的絢麗多彩的界面酷宵。
同步和異步
線程分同步sync
和異步async
之分
- 同步線程:同步線程會(huì)阻塞當(dāng)前線程去執(zhí)行線程內(nèi)的任務(wù),執(zhí)行完之后才會(huì)反回當(dāng)前線程躬窜。
- 異步線程:異步線程不會(huì)阻塞當(dāng)前線程浇垦,會(huì)開啟其他線程去執(zhí)行線程內(nèi)的任務(wù)。(推薦使用)
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"異步執(zhí)行任務(wù),不會(huì)阻塞當(dāng)前線程");
});
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"同步執(zhí)行任務(wù),注意——>");//這段代碼不會(huì)打印荣挨,會(huì)產(chǎn)生死鎖男韧,因?yàn)橥街骶€程會(huì)造成主隊(duì)列線程相互等待朴摊。
});
隊(duì)列
GCD中一個(gè)block代碼塊就是一個(gè)隊(duì)列,隊(duì)列可以是并行也可以是串行的煌抒。默認(rèn)情況下仍劈,它們是串行的,也就是說寡壮,任何給定的時(shí)間內(nèi)贩疙,只能有一個(gè)單獨(dú)的 block 運(yùn)行。隊(duì)列也可以是并行的况既,也就是同一時(shí)間內(nèi)允許多個(gè) block 一起執(zhí)行这溅。其實(shí)隊(duì)列很大程度的幫助我們更方便的使用多線程來調(diào)度我們的功能。
主線程隊(duì)列
1.獲取主線程串行隊(duì)列
dispatch_queue_t mainQueue = dispatch_get_main_queue();//注意:禁止再次隊(duì)列中同步執(zhí)行任務(wù)棒仍。因?yàn)闀?huì)產(chǎn)生死鎖
2.主線程串行隊(duì)列異步執(zhí)行任務(wù)悲靴,在主線程運(yùn)行,不會(huì)產(chǎn)生死鎖
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
NSLog(@"主隊(duì)列");
});
全局并發(fā)隊(duì)列
耗時(shí)的操作莫其,比如讀取網(wǎng)絡(luò)數(shù)據(jù)癞尚,IO,數(shù)據(jù)庫(kù)讀寫等,我們會(huì)在另外一個(gè)線程中處理這些操作乱陡,然后通知主線程更新界面
1.獲取全局并發(fā)隊(duì)列
//全局并發(fā)隊(duì)列中 GCD 為我們提供了優(yōu)先級(jí)
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.多個(gè)線程任務(wù)在全局并發(fā)隊(duì)列中執(zhí)行
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"current task");
dispatch_async(globalQueue, ^{
NSLog(@"最先加入全局并發(fā)隊(duì)列");
});
dispatch_async(globalQueue, ^{
NSLog(@"次加入全局并發(fā)隊(duì)列");
});
NSLog(@"next task");
控制臺(tái)輸出:
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] 最先加入全局并發(fā)隊(duì)列
2015-11-18 16:54:52.205 Whisper[39827:403291] 次加入全局并發(fā)隊(duì)列
異步線程的執(zhí)行順序是不確定的浇揩。幾乎同步開始執(zhí)行
全局并發(fā)隊(duì)列由系統(tǒng)默認(rèn)生成的,所以無(wú)法調(diào)用dispatch_resume()和dispatch_suspend()來控制執(zhí)行繼續(xù)或中斷憨颠。
自定義隊(duì)列
自定義隊(duì)列就是拋開系統(tǒng)為我們創(chuàng)建的全局主隊(duì)列以及全局并發(fā)隊(duì)列胳徽,自己創(chuàng)建一個(gè)隊(duì)列
//自定義串行隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("com.custom.serialQueue", DISPATCH_QUEUE_SERIAL);
//自定義并行隊(duì)列
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.custom.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_create
后面第一個(gè)參數(shù)通常用反域名字符表示,你可以作為你識(shí)別的唯一名稱爽彤,方便調(diào)試
有了隊(duì)列我們就可以添加任務(wù)來執(zhí)行了
示例:
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"current task");
dispatch_async(conCurrentQueue, ^{
NSLog(@"先加入隊(duì)列");
});
dispatch_async(conCurrentQueue, ^{
NSLog(@"次加入隊(duì)列");
});
NSLog(@"next task");
控制臺(tái)輸出如下:
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] 次加入隊(duì)列
2015-11-19 10:45:22.290 Whisper[1050:26500] 先加入隊(duì)列
隊(duì)列組
當(dāng)遇到需要執(zhí)行多個(gè)線程并發(fā)執(zhí)行养盗,然后等多個(gè)線程都結(jié)束之后,再匯總執(zhí)行結(jié)果時(shí)可以用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(@"并行任務(wù)1");
});
dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
NSLog(@"并行任務(wù)2");
});
dispatch_group_notify(groupQueue, mainQueue, ^{
NSLog(@"groupQueue中的任務(wù) 都執(zhí)行完成,回到主線程更新UI");
});
NSLog(@"next task");
控制臺(tái)輸出:
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] 并行任務(wù)1
2017-08-15 17:42:42.356 TestProject[21907:682849] 并行任務(wù)2
2017-08-15 17:42:42.504 TestProject[21907:682737] groupQueue中的任務(wù) 都執(zhí)行完成,回到主線程更新UI
//可以阻塞當(dāng)前線程 起到延遲等待效果
dispatch_group_wait(groupQueue, delayTime);
GCD 系統(tǒng)常用的 dispatch
方法
1.dispatch_once 實(shí)現(xiàn)單利模式
+ (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 只會(huì)運(yùn)行一次适篙。并且在連續(xù)的調(diào)用中往核,這種檢查是很高效的
2.dispatch_after
被用作延遲添加
dispatch_queue_t mainQueue = dispatch_get_main_queue();
NSLog(@"current task");
dispatch_after(delayTime3, mainQueue, ^{
NSLog(@"3秒之后添加到隊(duì)列");
});
dispatch_after(delayTime2, mainQueue, ^{
NSLog(@"2秒之后添加到隊(duì)列");
});
NSLog(@"next task");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"延遲兩秒執(zhí)行");
});
3.dispatch_apply
dispatch_apply函數(shù)的功能:把一項(xiàng)任務(wù)提交到隊(duì)列中多次執(zhí)行,隊(duì)列可以是串行也可以是并行嚷节,dispatch_apply不會(huì)立刻返回铆铆,在執(zhí)行完block中的任務(wù)后才會(huì)返回,是同步執(zhí)行的函數(shù)丹喻。
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(@"執(zhí)行完成");
控制臺(tái)輸出:
//如果 seriaQueue 為并行隊(duì)列 index 也可能是無(wú)須輸出
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] 執(zhí)行完成
4.dispatch_barrier_async 柵欄的作用
功能:是在并行隊(duì)列中,等待在dispatch_barrier_async之前加入的隊(duì)列全部執(zhí)行完成之后(這些任務(wù)是并發(fā)執(zhí)行的)再執(zhí)行dispatch_barrier_async中的任務(wù)翁都,dispatch_barrier_async中的任務(wù)執(zhí)行完成之后碍论,再去執(zhí)行在dispatch_barrier_async之后加入到隊(duì)列中的任務(wù)(這些任務(wù)是并發(fā)執(zhí)行的)。
示例:
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");
});
控制臺(tái)輸出:
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