養(yǎng)成好習(xí)慣藕施,把學(xué)過的東西都留一手宋渔,如有錯(cuò)請(qǐng)指示
基本概念
-
進(jìn)程
進(jìn)程是指系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序川陆,針對(duì)于iOS來說毁靶,就是開啟了一個(gè)app胧奔,這個(gè)app的運(yùn)行就是一個(gè)進(jìn)程
-
線程
一個(gè)進(jìn)程要想執(zhí)行任務(wù),那么就必須得有線程预吆,一個(gè)進(jìn)程至少得有一個(gè)線程
-
多線程的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1.能適當(dāng)?shù)奶岣叱绦虻倪\(yùn)行效率
2.能適當(dāng)?shù)奶岣遚pu的利用率
缺點(diǎn)
1.開啟線程需要棧和寄存器等內(nèi)存消耗龙填,默認(rèn)的一條線程占用棧去512kb
2.線程過多會(huì)導(dǎo)致CPU在線程上的消耗比較大
3.線程過多,程序設(shè)計(jì)就復(fù)雜了
-
并發(fā)與并行
并發(fā)
并發(fā):描述的是多個(gè)任務(wù)同時(shí)發(fā)生拐叉,都需要被處理岩遗,這是一種現(xiàn)象,側(cè)重點(diǎn)在發(fā)生
并行
并行:指的是一種技術(shù)凤瘦,一個(gè)同時(shí)處理多個(gè)任務(wù)的技術(shù)宿礁,側(cè)重點(diǎn)在運(yùn)行
總結(jié)
我們說的多線程,其實(shí)就是采取了并行技術(shù)蔬芥,從而提高執(zhí)行效率梆靖,因?yàn)橛袀€(gè)多個(gè)線程控汉,所以計(jì)算機(jī)的多個(gè)cpu可以同時(shí)工作,處理不同線程內(nèi)的指令返吻,但是對(duì)于單核的cpu而言姑子,多線程其實(shí)cpu在多個(gè)線程不停的調(diào)度,并發(fā)是一種現(xiàn)象思喊,面對(duì)這一現(xiàn)象壁酬,我們首先創(chuàng)建多個(gè)線程,真正加快程序運(yùn)行速度的是并行技術(shù)恨课,也就是讓多個(gè)cpu同時(shí)工作舆乔,而多線程是為了讓cpu同時(shí)工作成為可能,而對(duì)于單核的cpu剂公,就是讓cpu能在各個(gè)線程調(diào)度稱為可能
NSOperation & NSOperationQueue
簡(jiǎn)介:把要執(zhí)行的任務(wù)封裝到一個(gè)操作對(duì)象(operation object)希俩,并將操作對(duì)象放入操作隊(duì)列(nsoperationqueue),然后系統(tǒng)就會(huì)自動(dòng)在執(zhí)行任務(wù)纲辽。至于同步還是異步颜武、串行還是并行請(qǐng)繼續(xù)往下看
-
NSOperation的兩個(gè)子類
1.NSInvocationOperation
2.NSBlockOperation
GCD
-
同步任務(wù)與異步任務(wù)
任務(wù):即操作,在gcd當(dāng)中就是一個(gè)block拖吼,任務(wù)執(zhí)行的兩種方式:同步執(zhí)行 和 異步執(zhí)行
同步任務(wù)(sync)和異步任務(wù)(async)的主要區(qū)別在于會(huì)不會(huì)阻塞當(dāng)前線程鳞上,直到block中的任務(wù)執(zhí)行完畢
同步任務(wù)(sync):它會(huì)阻塞當(dāng)前線程并等待block中的任務(wù)執(zhí)行完畢,然后當(dāng)前線程才會(huì)繼續(xù)往下運(yùn)行
異步任務(wù)(async):當(dāng)前線程會(huì)直接往下執(zhí)行吊档,不用等著當(dāng)前任務(wù)執(zhí)行完篙议,并不會(huì)阻塞當(dāng)前線程
同步:只能在當(dāng)前線程執(zhí)行任務(wù),不具備開啟新線程的能力
異步:可以在新的線程執(zhí)行任務(wù)怠硼,具備開啟新線程的能力
-
隊(duì)列
-
串行隊(duì)列:先進(jìn)先出隊(duì)列鬼贱,每次只執(zhí)行一個(gè)任務(wù),線程任務(wù)按先后順序逐個(gè)執(zhí)行(需要等待隊(duì)列里面前面的任務(wù)執(zhí)行完之后再執(zhí)行新的任務(wù))
-
-
并發(fā)隊(duì)列:先進(jìn)先出隊(duì)列,不過可以形成多個(gè)任務(wù)并發(fā)香璃,也就是說这难,雖然也是FIFO,但是不同的是葡秒,它取出來一個(gè)任務(wù)就放到別的線程姻乓,然后再取出來一個(gè)放到別的線程,動(dòng)作很快同云,看起來所有的任務(wù)都是一起執(zhí)行的糖权,不過gcd會(huì)根據(jù)系統(tǒng)資源控制并行的數(shù)量,多個(gè)任務(wù)按添加順序一起開始執(zhí)行(不用等待前面的任務(wù)執(zhí)行完再執(zhí)行新的任務(wù)),但是添加間隔往往忽略不計(jì)炸站,所以看著像是一起執(zhí)行的
-
主隊(duì)列:這個(gè)是一個(gè)特殊的串行隊(duì)列星澳,隊(duì)列中的每個(gè)任務(wù)一定執(zhí)行在主線程中,如果主線程上有任務(wù)在執(zhí)行,主隊(duì)列就不會(huì)調(diào)度任務(wù)
-
總結(jié)
關(guān)于同步異步旱易、串行并行和線程的關(guān)系禁偎,下面通過一個(gè)表格來總結(jié)
可以看到腿堤,同步方法不一定在本線程如暖,異步方法方法也不一定新開線程(考慮主隊(duì)列)笆檀。
- 開不開線程,取決于執(zhí)行任務(wù)的函數(shù),同步不開,異步才能開
- 開幾條線程,取決于隊(duì)列,串行開一條,并發(fā)可以開多條(異步)
隊(duì)列是負(fù)責(zé)調(diào)度任務(wù)的,同步異步負(fù)責(zé)執(zhí)行任務(wù)
串行隊(duì)列和并發(fā)隊(duì)列的區(qū)別:會(huì)不會(huì)阻塞當(dāng)前隊(duì)列(阻塞的意思:隊(duì)列里的任務(wù)不用執(zhí)行完盒至,就可以拿出下一個(gè)任務(wù))
同步和異步的區(qū)別:會(huì)不會(huì)阻塞當(dāng)前線程(阻塞的意思:不用等待當(dāng)前的任務(wù)是否完成酗洒,就可以執(zhí)行下一個(gè)任務(wù))
串行隊(duì)列 并發(fā)隊(duì)列 demo
-(void)gcdDemo8{
/*
全局隊(duì)列 & 并發(fā)隊(duì)列
1> 名稱,并發(fā)隊(duì)列取名字,適合于企業(yè)開發(fā)跟蹤錯(cuò)誤
2> release,在MRC 并發(fā)隊(duì)列 需要使用的
dispatch_release(q);//ARC 情況下不需要release !
全局隊(duì)列 & 串行隊(duì)列
全局隊(duì)列: 并發(fā),能夠調(diào)度多個(gè)線程,執(zhí)行效率高
- 費(fèi)電
串行隊(duì)列:一個(gè)一個(gè)執(zhí)行,執(zhí)行效率低
- 省點(diǎn)
判斷依據(jù):用戶上網(wǎng)方式
- WIFI : 可以多開線程
- 流量 : 盡量少開線程
*/
//1.隊(duì)列
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i< 10; i++) {
NSLog(@" %d",i);
dispatch_async(q, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
NSLog(@"come here");
}
//MARK: 全局隊(duì)列 (本質(zhì)上并發(fā)隊(duì)列)
-(void)gcdDemo7{
//全局隊(duì)列
/* 參數(shù)
1. 涉及到系統(tǒng)適配
iOS 8 服務(wù)質(zhì)量
QOS_CLASS_USER_INTERACTIVE 用戶交互(希望線程快速被執(zhí)行,不要用好使的操作)
QOS_CLASS_USER_INITIATED 用戶需要的(同樣不要使用耗時(shí)操作)
QOS_CLASS_DEFAULT 默認(rèn)的(給系統(tǒng)來重置隊(duì)列的)
QOS_CLASS_UTILITY 使用工具(用來做耗時(shí)操作)
QOS_CLASS_BACKGROUND 后臺(tái)
QOS_CLASS_UNSPECIFIED 沒有指定優(yōu)先級(jí)
iOS 7 調(diào)度的優(yōu)先級(jí)
- DISPATCH_QUEUE_PRIORITY_HIGH 2 高優(yōu)先級(jí)
- DISPATCH_QUEUE_PRIORITY_DEFAULT 0 默認(rèn)優(yōu)先級(jí)
- DISPATCH_QUEUE_PRIORITY_LOW (-2) 低優(yōu)先級(jí)
- DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后臺(tái)優(yōu)先級(jí)
提示:尤其不要選擇BACKGROUND 優(yōu)先級(jí),服務(wù)質(zhì)量,線程執(zhí)行會(huì)慢到令人發(fā)指!!!
2. 為未來使用的一個(gè)保留,現(xiàn)在始終給0.
老項(xiàng)目中,一般還是沒有淘汰iOS 7 ,沒法使用服務(wù)質(zhì)量
*/
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
for (int i = 0; i< 10; i++) {
dispatch_async(q, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
NSLog(@"come here");
}
#pragma mark - <同步任務(wù)>
//MARK : 增強(qiáng)版同步任務(wù)
// 可以隊(duì)列調(diào)度多個(gè)任務(wù)前,指定一個(gè)同步任務(wù),讓所有的異步任務(wù),等待同步任務(wù)執(zhí)行完成,這就是依賴關(guān)系
// - 同步任務(wù),會(huì)造成一個(gè)死鎖!
-(void)gcdDemo6{
//隊(duì)里
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
//任務(wù)
void (^task)()=^{
for (int i = 0; i < 10; i++) {
NSLog(@"%d %@",i ,[NSThread currentThread]);
if (i==5) {
//1.用戶登錄
dispatch_sync(q, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"用戶登錄 %@",[NSThread currentThread]);
}
});
}
}
//2.支付
dispatch_async(q, ^{
NSLog(@"支付 %@",[NSThread currentThread]);
});
//3.下載
dispatch_async(q, ^{
NSLog(@"下載 %@",[NSThread currentThread]);
});
};
dispatch_async(q, task);
// NSLog(@"come here");
}
//MARK - 同步任務(wù)作用!
/**
在開發(fā)中,通常會(huì)將耗時(shí)操作放后臺(tái)執(zhí)行,有的時(shí)候,有些任務(wù)彼此有"依賴"關(guān)系!
例子: 登錄,支付,下載
利用同步任務(wù),能夠做到任務(wù)依賴關(guān)系,前一個(gè)任務(wù)是同步任務(wù),哥么不執(zhí)行完,隊(duì)列就不會(huì)調(diào)度后面的任務(wù)
*/
-(void)gcdDemo5{
dispatch_queue_t loginQueue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
//1.用戶登錄
dispatch_sync(loginQueue, ^{
NSLog(@"用戶登錄 %@",[NSThread currentThread]);
});
//2.支付
dispatch_async(loginQueue, ^{
NSLog(@"支付 %@",[NSThread currentThread]);
});
//3.下載
dispatch_async(loginQueue, ^{
NSLog(@"下載 %@",[NSThread currentThread]);
});
for (int i = 0; i< 10; i++) {
NSLog(@"......%@",[NSThread currentThread]);
}
}
//MARK : 并發(fā)隊(duì)列,同步執(zhí)行 和 串行隊(duì)列,同步執(zhí)行 效果一樣!
-(void)gcdDemo4{
// 會(huì)開線程嗎? 順序執(zhí)行? come here?
// 不會(huì) 順序 最后
//1.隊(duì)列 - 并發(fā) DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
//2.同步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_sync(q, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
//哥么在主線程!
NSLog(@"come here");
}
//MARK : 并發(fā)隊(duì)列,異步執(zhí)行
-(void)gcdDemo3{
//1.隊(duì)列 - 并發(fā) DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
//2.異步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_async(q, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
//哥么在主線程!
NSLog(@"come here");
}
//MARK: 串行隊(duì)列,異步任務(wù)
-(void)gcdDemo2{
/**
會(huì)開幾條線程?會(huì)順序執(zhí)行嗎?
*/
//1.隊(duì)列 - 串行
dispatch_queue_t q = dispatch_queue_create("test", NULL);
//2.異步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
NSLog(@"%d------------",i);
dispatch_async(q, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
//哥么在主線程!
NSLog(@"come here");
}
//MARK:串行隊(duì)列,同步任務(wù)
/**
* 不會(huì)開啟線程,會(huì)順序執(zhí)行
*/
-(void)gcdDemo1{
//1.隊(duì)列 - 串行
/**
1.隊(duì)列名稱:
2.隊(duì)列的屬性: DISPATCH_QUEUE_SERIAL 標(biāo)示串行!
*/
dispatch_queue_t q = dispatch_queue_create("test", NULL);
//2.同步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_sync(q, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
}
主隊(duì)列
重點(diǎn):主隊(duì)列,以FIFO調(diào)度任務(wù),如果主線程上有任務(wù)在執(zhí)行,主隊(duì)列就不會(huì)調(diào)度任務(wù),如下代碼能體現(xiàn)
- 主要是負(fù)責(zé)在主線程上執(zhí)行任務(wù)
- (void)gcdDemo1 {
//主隊(duì)列是專門負(fù)責(zé)在主線程上調(diào)度任務(wù)的隊(duì)列 --> 不會(huì)開線程
//1.隊(duì)列 --> 已啟動(dòng)主線程,就可以獲取主隊(duì)列
dispatch_queue_t q = dispatch_get_main_queue();
//2.異步任務(wù)
dispatch_async(q, ^{
NSLog(@"111==%@",[NSThread currentThread]);
});
NSLog(@"come here");
NSLog(@"come here1");
NSLog(@"come here2");
NSLog(@"come here3");
dispatch_async(q, ^{
NSLog(@"222==%@",[NSThread currentThread]);
});
[self test];
/*
這么理解哈枷遂,整個(gè)gcdDemo1e也相當(dāng)于任務(wù)在主隊(duì)列里執(zhí)行
test 方法就一個(gè)耗時(shí)操作
打印順序是
come here
come here1
come here2
come here3
test的for循環(huán)打印
3333 (3333是touch方法調(diào)用gcdDemo1e后的一個(gè)打印語句)
111==
222==
如果主線程上有任務(wù)在執(zhí)行,主隊(duì)列就不會(huì)調(diào)度任務(wù)
所以在主隊(duì)列里異步執(zhí)行任務(wù)樱衷,就要等主隊(duì)列的其他任務(wù)都執(zhí)行完了,在執(zhí)行block的任務(wù)
*/
}
- (void)gcdDemo2 {
//主隊(duì)列是專門負(fù)責(zé)在主線程上調(diào)度任務(wù)的隊(duì)列 --> 不會(huì)開線程
NSLog(@"這里!!");
//1.隊(duì)列 --> 已啟動(dòng)主線程,就可以獲取主隊(duì)列
dispatch_queue_t q = dispatch_get_main_queue();
//2.同步任務(wù) ==> 死鎖
dispatch_sync(q, ^{
NSLog(@"能來嗎? ");
});
NSLog(@"come here");
/*
為什么是死鎖呢
跟gcdDemo1的解釋一樣
整個(gè)gcdDemo2 包括gcdDemo2后面的都相當(dāng)于一個(gè)任務(wù)在主線程里執(zhí)行酒唉,
所以必須要等這個(gè)任務(wù)都執(zhí)行完了再去執(zhí)行dispatch_sync的任務(wù)
但是dispatch_sync又是阻塞當(dāng)前線程的矩桂,也就是說dispatch_sync下面的代碼要等到dispatch_sync里面的任務(wù)執(zhí)行完再去執(zhí)行,這不就相互等待痪伦,誰也等不到誰侄榴,所以就死鎖了
*/
}
-
GCD死鎖
1.死鎖1
NSLog(@"111111");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2222222");
});
NSLog(@"3333333");
出現(xiàn)的打印現(xiàn)象:只打印了“111111”,并且主線程已卡死网沾,點(diǎn)擊啊什么的都沒有效果了癞蚕,這個(gè)就是傳說中死鎖,但是在xcode8之后死鎖直接報(bào)錯(cuò)辉哥,如下所示
解釋:同步任務(wù)會(huì)阻塞當(dāng)前線程涣达,然后把block中的任務(wù),只有等到block中的任務(wù)完成后才會(huì)讓當(dāng)前線程繼續(xù)往下走证薇。這段代碼的步驟:打印完第一句后,dispatch_sync 立即阻塞當(dāng)前的主線程匆篓,這里關(guān)于死鎖的描述有些簡(jiǎn)書模糊浑度,“然后把 Block 中的任務(wù)放到 main_queue 中,可是 main_queue 中的任務(wù)會(huì)被取出來放到主線程中執(zhí)行鸦概,但主線程這個(gè)時(shí)候已經(jīng)被阻塞了箩张,所以 Block 中的任務(wù)就不能完成”,這里“main_queue 中的任務(wù)會(huì)被取出來放到主線程中執(zhí)行”描述不準(zhǔn)確窗市,應(yīng)該是main_queue中已經(jīng)有任務(wù)在執(zhí)行了先慷,而這個(gè)任務(wù)就包含了同步任務(wù),而同步任務(wù)中的block卻被放到了列隊(duì)底部咨察,由于同步任務(wù)需要阻塞當(dāng)前線程论熙,完成block才能繼續(xù)執(zhí)行,而隊(duì)列又無法彈出該block來執(zhí)行摄狱,因?yàn)檫@時(shí)候在隊(duì)列頂部的是包含了block的任務(wù)脓诡,形成了循環(huán)依賴
2.死鎖2
dispatch_queue_t cusQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
NSLog(@"111111");
dispatch_async(cusQueue, ^{
NSLog(@"2222222");
dispatch_sync(cusQueue, ^{
NSLog(@"3333333");
});
NSLog(@"44444444");
});
NSLog(@"5555555");
出現(xiàn)的打印現(xiàn)象:
解釋:
1.創(chuàng)建的cusQueue是serial,這個(gè)是串行隊(duì)列
2.打印出1111
3.dispatch_async是異步執(zhí)行无午,所以當(dāng)前線程不會(huì)阻塞,于是有了兩條線程這是并行的祝谚,那么22222和5555打印的先后是不確定的
4.注意宪迟,高潮來了。現(xiàn)在的情況和上一個(gè)例子一樣了交惯。dispatch_sync同步執(zhí)行次泽,于是它所在的線程會(huì)被阻塞,一直等到 sync 里的任務(wù)執(zhí)行完才會(huì)繼續(xù)往下席爽。于是 sync 就高興的把自己 Block 中的任務(wù)放到 queue 中意荤,可誰想 queue 是一個(gè)串行隊(duì)列,一次執(zhí)行一個(gè)任務(wù)拳昌,所以 sync 的 Block 必須等到前一個(gè)任務(wù)執(zhí)行完畢袭异,可萬萬沒想到的是 queue 正在執(zhí)行的任務(wù)就是被 sync 阻塞了的那個(gè)。于是又發(fā)生了死鎖炬藤。所以 sync 所在的線程被卡死了御铃。剩下的兩句代碼自然不會(huì)打印。
3.之前誤以為是死鎖
dispatch_queue_t myQueue =dispatch_queue_create("myQueue", NULL);
NSLog(@"111111 :%d",[NSThread isMainThread]);
dispatch_sync(myQueue, ^{
NSLog(@"3333333 :%d",[NSThread isMainThread]);
// dispatch_sync(myQueue, ^{
// NSLog(@"44444 :%d",[NSThread //isMainThread]);
// });
});
NSLog(@"5555555 :%d",[NSThread isMainThread]);
之前認(rèn)為沈矿,同步任務(wù) + 串行隊(duì)列 就是死鎖上真,因?yàn)橹罢J(rèn)為同步任務(wù)會(huì)阻塞了當(dāng)前線程,而串行隊(duì)列的任務(wù)被取出來會(huì)在當(dāng)前線程執(zhí)行羹膳,所以就會(huì)被死鎖睡互,這個(gè)例子根第一個(gè)死鎖很相似,區(qū)別就是第一個(gè)例子是主隊(duì)列陵像,而這個(gè)例子是串行隊(duì)列就珠。那么現(xiàn)在開始解釋這個(gè)為什么不是死鎖
1.第一句代碼是創(chuàng)建一個(gè)串行隊(duì)列
2.第二句代碼的1111能打印出來這個(gè)毋庸置疑
3.重點(diǎn)來了,第三句代碼醒颖,同步任務(wù)會(huì)阻塞當(dāng)前線程妻怎,這個(gè)也是肯定的,把任務(wù)放入這個(gè)自己創(chuàng)建的串行隊(duì)列泞歉,并且這個(gè)隊(duì)列之前是沒有任務(wù)的逼侦,所以代碼會(huì)執(zhí)行完這個(gè)block里的代碼再返回繼續(xù)走之后的代碼,
4.所以順序是 111 333 555腰耙,并不會(huì)死鎖
5.而第一例子之所以會(huì)造成死鎖榛丢,那是因?yàn)榘讶蝿?wù)放入的是主隊(duì)了,而執(zhí)行sync那句代碼也是在主隊(duì)列中挺庞,執(zhí)行sync時(shí)線程已經(jīng)阻塞晰赞,再把block的任務(wù)取出來是必須要等sync返回才能執(zhí)行,因?yàn)閟ync是比block先入隊(duì)列,出隊(duì)列是先進(jìn)的先出宾肺,所以相互等待就是死鎖
6.如果這個(gè)例子溯饵,把注釋掉的代碼打開,那么也是死鎖锨用,因?yàn)榈诙€(gè)sync是串行隊(duì)列的第一個(gè)任務(wù)丰刊,而block是串行隊(duì)列的第二個(gè)任務(wù),于是又是相互等待造成死鎖
4.死鎖總結(jié)
死鎖的原因不是線程阻塞增拥,而是隊(duì)列阻塞
如果dispatch_sync()的目標(biāo)queue為當(dāng)前queue啄巧,會(huì)發(fā)生死鎖(并行queue并不會(huì))。使用dispatch_sync()會(huì)遇到跟我們?cè)趐thread中使用mutex鎖一樣的死鎖問題
-
GCD常用方法
dispatch_after
NSLog(@"111111"); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"22222"); }); dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 3); dispatch_after(delayTime, dispatch_get_main_queue(), ^{ NSLog(@"33333"); });
dispatch_after只是延時(shí)提交block掌栅,并不是延時(shí)后立即執(zhí)行的秩仆,dispatch_after不是很精確
dispatch_apply
dispatch_queue_t cusQueue = dispatch_queue_create("cus", DISPATCH_QUEUE_CONCURRENT);
//第一個(gè)參數(shù),3--block執(zhí)行的次數(shù)
//第二個(gè)參數(shù)猾封,applyQueue--block任務(wù)提交到的隊(duì)列
//第三個(gè)參數(shù)澄耍,block--需要重復(fù)執(zhí)行的任務(wù)
dispatch_apply(3, cusQueue, ^(size_t index) {
NSLog(@"current index %@",@(index));
sleep(1);
});
NSLog(@"2222");
dispatch_apply:把一項(xiàng)任務(wù)放入隊(duì)列中多次執(zhí)行,串行隊(duì)列和并行隊(duì)列都行晌缘,它是同步執(zhí)行的函數(shù)齐莲,不會(huì)立刻返回,要等待block中的任務(wù)全部執(zhí)行完才返回
dispatch_apply的正確使用方法:為了不阻塞主線程磷箕,一般把dispatch_apply放入異步隊(duì)列中調(diào)用选酗,然后執(zhí)行完后通知主線程
dispatch_once
保證app在運(yùn)行期間,block中的代碼只執(zhí)行一次岳枷,個(gè)人用的最多的就是單例的使用中
dispatch group
有時(shí)候我們會(huì)有這種需求芒填,在剛進(jìn)去一個(gè)頁面需要發(fā)送兩個(gè)請(qǐng)求,并且某種特定操作必須在兩個(gè)請(qǐng)求都結(jié)束(成功或失斂辗薄)的時(shí)候才會(huì)執(zhí)行殿衰,最low的辦法第二個(gè)請(qǐng)求嵌套在第一個(gè)請(qǐng)求結(jié)果后在發(fā)送,在第二個(gè)請(qǐng)求結(jié)束后再執(zhí)行操作盛泡。還有就是只使用一個(gè)Serial Dispatch Queue播玖,把想要執(zhí)行的操作全部追加到這個(gè)Serial Dispatch Queue中并在最后追加某種特定操作,頗為復(fù)雜操作饭于。但是呢,我們這里介紹更高級(jí)的辦法使用dispatch group
dispatch_queue_t cusConQueue = dispatch_queue_create("cusConQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t cusGroup = dispatch_group_create();
dispatch_group_async(cusGroup, cusConQueue, ^{
NSLog(@"執(zhí)行任務(wù)1");
});
dispatch_group_async(cusGroup, cusConQueue, ^{
NSLog(@"執(zhí)行任務(wù)2");
});
dispatch_group_async(cusGroup, cusConQueue, ^{
NSLog(@"執(zhí)行任務(wù)3");
});
dispatch_group_notify(cusGroup, cusConQueue, ^{
NSLog(@"執(zhí)行所有任務(wù)后想要的操作");
});
NSLog(@"44444----");
上圖中的 1 2 3 4執(zhí)行的順序都不一定维蒙,因?yàn)樗麄兌际钱惒剑? 2 3任務(wù)都執(zhí)行完成后才會(huì)執(zhí)行 notif里的任務(wù)
上面的dispatch_group_notify還可以換成dispatch_group_wait,代碼如下
dispatch_queue_t cusConQueue = dispatch_queue_create("cusConQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t cusGroup = dispatch_group_create();
dispatch_group_async(cusGroup, cusConQueue, ^{
NSLog(@"執(zhí)行任務(wù)1");
});
dispatch_group_async(cusGroup, cusConQueue, ^{
NSLog(@"執(zhí)行任務(wù)2");
});
dispatch_group_async(cusGroup, cusConQueue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"執(zhí)行任務(wù)3");
});
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1);
long result=dispatch_group_wait(cusGroup, DISPATCH_TIME_FOREVER);
if (result==0) {
NSLog(@"任務(wù)執(zhí)行完成");
}
else{
NSLog(@"任務(wù)執(zhí)行還在繼續(xù)");
}
NSLog(@"44444----");
dispatch_group_wait第二個(gè)參數(shù)指定為等待的時(shí)間(超時(shí))掰吕,屬于dispatch_time_t類型,在這里使用DISPATCH_TIME_FOREVER颅痊,意味著永久等待殖熟。如果dispatch group的處理尚未結(jié)束,就會(huì)一直等待斑响,它會(huì)阻塞線程菱属,所以不會(huì)放在主線程里執(zhí)行钳榨,所以如果group的任務(wù)沒有處理完,代碼是不會(huì)執(zhí)行dispatch_group_wait之后的代碼纽门,所以這里的打印 1 2 3 是無序薛耻,但是4一定是在最后
但是呢上面這種dispatch_group的排列執(zhí)行方式,是不會(huì)考慮block塊內(nèi)部的異步請(qǐng)求情況的赏陵,它只能保證把block內(nèi)的非異步直觀代碼執(zhí)行完饼齿,所以如果ABC三個(gè)任務(wù)中如果有執(zhí)行異步的請(qǐng)求,那么在dispatch_group_notify最終任務(wù)執(zhí)行中蝙搔,那個(gè)異步請(qǐng)求不一定毀掉結(jié)束缕溉,所以又給應(yīng)該介紹新的api
dispatch_group_enter/dispatch_group_leave
調(diào)用dispatch_group_enter這個(gè)方法標(biāo)志著一個(gè)代碼塊被加入了group,和dispatch_group_async功能類似吃型;
需要和dispatch_group_enter()证鸥、dispatch_group_leave()成對(duì)出現(xiàn);編譯器會(huì)強(qiáng)制識(shí)別當(dāng)出現(xiàn)dispatch_group_leave全部結(jié)束才執(zhí)行dispatch_group_notify
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(5);
NSLog(@"任務(wù)一完成");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(8);
NSLog(@"任務(wù)二完成");
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務(wù)完成");
});
dispatch_barrier_async
這個(gè)函數(shù)可以設(shè)置同步執(zhí)行的block勤晚,它會(huì)等到在它加入隊(duì)列之前的block執(zhí)行完畢后枉层,才開始執(zhí)行。在它之后加入隊(duì)列的block运翼,則等到這個(gè)block執(zhí)行完畢后才開始執(zhí)行
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", 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");
});
如上都是GCD一些常用的方法返干,還有一些不常用也沒去做記錄了