目錄:
1.GCD簡(jiǎn)介
2.串行隊(duì)列 + 同步執(zhí)行
3.串行隊(duì)列 + 異步執(zhí)行
4.并發(fā)隊(duì)列 + 同步執(zhí)行
5.并發(fā)隊(duì)列 + 異步執(zhí)行
6.全局隊(duì)列
7.主隊(duì)列
8.線程間通信
9.GCD柵欄函數(shù)(dispatch_barrier_async)
10.GCD調(diào)度組
一.GCD簡(jiǎn)介
注意:開啟線程的操作是CPU做的讥此,GCD只負(fù)責(zé)任務(wù)的調(diào)度倒慧。
(1).GCD中涉及到兩個(gè)十分重要的概念, 就是任務(wù)和隊(duì)列.
任務(wù)(Task): 你需要執(zhí)行的操作;
隊(duì)列(Queue): 存放任務(wù)的容器艺糜。
(2).GCD使用步驟一姿,2步。
????? 定制任務(wù)(確定想要做的事情);
??? ? 然后將任務(wù)添加到隊(duì)列中( GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出來见芹,放到對(duì)應(yīng)的線程中執(zhí)行。取任務(wù)遵循隊(duì)列FIFO原則:先添加進(jìn)隊(duì)列的任務(wù)先被取出來)蠢涝。
(3).GCD中的隊(duì)列分2類
?????? 并發(fā)隊(duì)列:可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(能夠開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))玄呛,并發(fā)功能只有在異步執(zhí)行函數(shù)下有效。
?????? 串行隊(duì)列:任務(wù)只能在同一條線程中(可以是主線程和二,也可以是子線程)一個(gè)一個(gè)按順序執(zhí)行徘铝。
(4).任務(wù)執(zhí)行分為同步執(zhí)行和異步執(zhí)行
? ? ? ? 同步執(zhí)行 :dispatch_sync(dispatch_queue_t? _Nonnull queue, ^(void)block),一個(gè)任務(wù)沒有結(jié)束,就不會(huì)去執(zhí)行下一個(gè)任務(wù)惕它。同步執(zhí)行函數(shù)無法開啟新線程怕午。
? ? ??? 異步執(zhí)行: dispatch_async(dispatch_queue_t? _Nonnull queue, ^(void)block),不用等待任務(wù)執(zhí)行完淹魄,就可以執(zhí)行下一個(gè)任務(wù)郁惜。異步執(zhí)行函數(shù)有能力開啟新線程。
二.各種情況詳細(xì)分析
?
? ?? (1).串行隊(duì)列 + 同步執(zhí)行
? ?????? //1.隊(duì)列 -- 串行 DISPATCH_QUEUE_SERIAL 串行 等價(jià)于NULL
???????? dispatch_queue_t q = dispatch_queue_create("CC_GCD", NULL);
??????? //2.先循環(huán)添加任務(wù)揭北,同步執(zhí)行任務(wù)
???????? for (int i = 0;? i < 10; i++) {
??????????????? dispatch_sync(q, ^{
????????????????????????? NSLog(@"%@扳炬,%d",[NSThread currentThread],i);
?????????? });
??? 分析:首先創(chuàng)建了一個(gè)串行隊(duì)列,然后循環(huán)向隊(duì)列中添加10個(gè)任務(wù)搔体,調(diào)用GCD同步執(zhí)行函數(shù)執(zhí)行隊(duì)列中的任務(wù)恨樟。 由于是同步執(zhí)行所以不會(huì)開啟新的線程,任務(wù)都添加在串行隊(duì)列疚俱,所以這些打印會(huì)按順序執(zhí)行劝术,且都在主線程中執(zhí)行。
??? (2).串行隊(duì)列 + 異步執(zhí)行
??????????? //1.隊(duì)列 -- 串行 DISPATCH_QUEUE_SERIAL 串行 等價(jià)于NULL
??????????? dispatch_queue_t q = dispatch_queue_create("CC_GCD", NULL);
? ? ? ? ? //2..先循環(huán)添加任務(wù)呆奕,異步執(zhí)行任務(wù)
?????????? for (int i = 0;? i < 10; i++) {
???????????????? NSLog(@"%d------------- ",i);
???????????????? dispatch_async(q, ^{
???????????? ? ?? NSLog(@"%@养晋,%d",[NSThread currentThread],i);
???????????????? });
?????? ? ? }
????????? NSLog(@"come here");
分析:首先創(chuàng)建了一個(gè)串行隊(duì)列,然后循環(huán)向隊(duì)列中添加10個(gè)任務(wù)梁钾,調(diào)用GCD異步執(zhí)行函數(shù)執(zhí)行隊(duì)列中的任務(wù)绳泉。 由于是異步執(zhí)行所以會(huì)開啟新的線程,任務(wù)都添加在串行隊(duì)列姆泻,所以這些打印會(huì)按順序執(zhí)行零酪,但是是在新的線程中執(zhí)行,子線程只會(huì)開啟1條拇勃。
??? (3).并發(fā)隊(duì)列 + 同步執(zhí)行
?????????????? //1.隊(duì)列 DISPATCH_QUEUE_CONCURRENT
????????????? dispatch_queue_t q = dispatch_queue_create("CC_GCD", DISPATCH_QUEUE_CONCURRENT);
???????????? //2.同步執(zhí)行任務(wù)
???????????? for (int i = 0;? i < 10; i++) {
????????? ? ? ? ? ? NSLog(@"%d------------- ",i);
?????????? ? ? ? ?? dispatch_sync(q, ^{
?????????????????????? ? ? ? NSLog(@"%@四苇,%d",[NSThread currentThread],i);
??????????????????? });
????????????? }
????????????? NSLog(@"come here");
分析:首先創(chuàng)建了一個(gè)并發(fā)隊(duì)列,然后循環(huán)向隊(duì)列中添加10個(gè)任務(wù)方咆,調(diào)用GCD同步執(zhí)行函數(shù)執(zhí)行隊(duì)列中的任務(wù)月腋。 由于是同步執(zhí)行所以不會(huì)開啟新的線程,任務(wù)都添加在并發(fā)隊(duì)列瓣赂,雖然我們說并發(fā)隊(duì)列里面的任務(wù)可以同時(shí)取出來執(zhí)行榆骚,但是這里是同步執(zhí)行,沒有開啟新的線程煌集,所以這些打印還是會(huì)按順序執(zhí)行寨躁,且都在主線程中執(zhí)行。
??? (4).并發(fā)隊(duì)列 + 異步執(zhí)行
??????????????? //1.隊(duì)列 DISPATCH_QUEUE_CONCURRENT
??????????????? dispatch_queue_t q = dispatch_queue_create("CC_GCD", DISPATCH_QUEUE_CONCURRENT);
?????????????? //2.異步執(zhí)行任務(wù)
?????????????? for (int i = 0;? i < 10; i++) {
?????????????????????? NSLog(@"%d------------- ",i);
????????????????????? dispatch_async(q, ^{
?????????????????????????????? NSLog(@"%@牙勘,%d",[NSThread currentThread],i);
????????????? ? ? ? ? });
???????????? ?? }
??????????????? NSLog(@"come here");
分析:首先創(chuàng)建了一個(gè)并發(fā)隊(duì)列,然后循環(huán)向隊(duì)列中添加10個(gè)任務(wù),調(diào)用GCD異步執(zhí)行函數(shù)執(zhí)行隊(duì)列中的任務(wù)方面。 由于是異步執(zhí)行所以會(huì)開啟新的線程放钦,任務(wù)都添加在并發(fā)隊(duì)列,所以這十個(gè)任務(wù)能夠同時(shí)執(zhí)行恭金,那么久會(huì)開啟多條線程操禀,至于開啟幾條線程用CPU決定,程序員無法決定横腿。
? (5).全局隊(duì)列(本質(zhì)上是一個(gè)并發(fā)隊(duì)列)
?????? 創(chuàng)建全局隊(duì)列函數(shù):dispatch_get_global_queue(long identifier, unsigned long flags);
? ? ? 參數(shù)說明:? ? 參數(shù)一:涉及系統(tǒng)適配
?????????????????????????????????????? iOS 8.0 服務(wù)質(zhì)量
?????????????????????????????????????? QOS_CLASS_USER_INTERACTIVE? 用戶交互(希望線程快速執(zhí)行颓屑,不要放一些耗時(shí)操作)
?????????????????????????????????????? QOS_CLASS_USER_INITIATED? ? 用戶需要的(不要放一些耗時(shí)操作)
?????????????????????????????????????? QOS_CLASS_DEFAULT? ? ? ? ? 0 默認(rèn)
?????????????????????????????????????? QOS_CLASS_UTILITY? ? ? ? ? 使用工具(用來耗時(shí)操作)
?????????????????????????????????????? QOS_CLASS_BACKGROUND? ? ? ? 后臺(tái)
?????????????????????????????????????? QOS_CLASS_UNSPECIFIED? ? ? 沒有指定優(yōu)先級(jí)
?????????????????????????????????????? iOS 7.0 調(diào)度優(yōu)先級(jí)
?????????????????????????????????????? DISPATCH_QUEUE_PRIORITY_HIGH? ? ? 高優(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 后臺(tái)優(yōu)先級(jí)
? ? ? ? ? ? ? ? ? ? ? ? ? 參數(shù)二:為未來的保留參數(shù),
?????????????????????????????????????? 提示:尤其不要選擇BACKGROUND? 耿焊,線程執(zhí)行會(huì)慢到令人發(fā)指揪惦!
(6).主隊(duì)列(本質(zhì)上是一個(gè)并發(fā)隊(duì)列)
??????? 創(chuàng)建主隊(duì)列函數(shù):dispatch_get_main_queue(void)
??????? 注:主隊(duì)列上的任務(wù)只能夠在主線程上執(zhí)行,所以無論同步執(zhí)行還是異步執(zhí)行函數(shù)罗侯,都不會(huì)開啟新線程器腋。
??????? 主隊(duì)列+同步執(zhí)行
?????? NSLog(@"------start-------");
?????? dispatch_sync(dispatch_get_main_queue(), ^{
?????????????????? NSLog(@"download1-------%@",[NSThread currentThread]);
?????? });
?????? dispatch_sync(dispatch_get_main_queue(), ^{
?????????????????? NSLog(@"download1-------%@",[NSThread currentThread]);
???????? });
?????? dispatch_sync(dispatch_get_main_queue(), ^{
????????? ? ? ? ?? NSLog(@"download1-------%@",[NSThread currentThread]);
?????? });
????? NSLog(@"-------end---------");
分析:現(xiàn)在是直接崩潰了, 以前這種情況是會(huì)發(fā)生死鎖的。
????
? ? ? ?? 主隊(duì)列+異步函數(shù)
???????? // 1.獲得主隊(duì)列
??????? dispatch_queue_t queue = dispatch_get_main_queue();
??????? NSLog(@"-----start------");
????? // 2.將任務(wù)封裝到異步函數(shù)中 钩杰,添加任務(wù)到主隊(duì)列中
????? dispatch_async(queue, ^{
?????????????? NSLog(@"download1 ----- %@", [NSThread currentThread]);
?????? });
?????? dispatch_async(queue, ^{
????????????? NSLog(@"download2 ----- %@", [NSThread currentThread]);
????? });
????? dispatch_async(queue, ^{
????? NSLog(@"download3 ----- %@", [NSThread currentThread]);
????? });
???? NSLog(@"-----end------");
分析:不開線程纫塌,start和end執(zhí)行完后,主隊(duì)列中的任務(wù)串行在主線程執(zhí)行讲弄。
(7).? 線程間通信
???? // 1. 創(chuàng)建子線程處理耗時(shí)操作
??? dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
?? ? ? ? ? ? ? ? ? //1.1耗時(shí)操作開始
? ? ? ? ? ? ? ? ? for (int i = 0; i < 10000; i++) {
????? ? ? ? ? ? ? ? ? ? NSLog(@"---耗時(shí)操作-%@----%d", [NSThread currentThread],i);
? ? ? ? ? ? ? ?? }
? ? ? ? ? ? ?? //1.2耗時(shí)操作完成回到主線程中
? ? ? ? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{
??????? ? ? ? ? ? ? ? ? NSLog(@"----%@----", [NSThread currentThread]);
? ? ? ? ? ?? });
});
(8)GCD柵欄函數(shù)(dispatch_barrier_async)
?????????? dispatch_barrier_async函數(shù)的作用與barrier的意思相同,在進(jìn)程管理中起到一個(gè)柵欄的作用,它等待所有位于barrier函數(shù)之前的操作執(zhí)行完畢后執(zhí)行,并且在barrier函數(shù)執(zhí)行之后,barrier函數(shù)之后的操作才會(huì)得到執(zhí)行,該函數(shù)需要同dispatch_queue_create函數(shù)生成的concurrent Dispatch Queue隊(duì)列一起使用措左。
例:
輸出結(jié)果:
分析:前十個(gè) --> barrier -->后十個(gè)? 其中 前十個(gè) 與 后十個(gè) 由于并行處理先后順序不定
運(yùn)用場(chǎng)景:用barrier實(shí)現(xiàn): 讀-寫鎖,讀-寫鎖有以下幾個(gè)特點(diǎn):? 在沒有寫操作的時(shí)候, 可以任意的并發(fā)讀取, 在所有讀操作完成后, 才進(jìn)行寫操作, 但是寫操作不可以并發(fā), 且在寫操作過程中, 不能讀取, 在寫操作完成后, 又可以任意的并發(fā)讀取了避除。如果我們使用barrier GCD接口來處理寫操作, 使用普通的GCD接口來并發(fā)讀取, 那么完全滿足讀-寫鎖的以上特點(diǎn)
dispatch_barrier_sync和dispatch_barrier_async的區(qū)別:
在將任務(wù)插入到queue的時(shí)候怎披,dispatch_barrier_sync需要等待自己的任務(wù)結(jié)束之后才會(huì)繼續(xù)程序,然后插入被寫在它后面的任務(wù)驹饺,然后執(zhí)行后面的任務(wù)
而dispatch_barrier_async將自己的任務(wù)插入到queue之后钳枕,不會(huì)等待自己的任務(wù)結(jié)束,它會(huì)繼續(xù)把后面的任務(wù)插入到queue
所以赏壹,dispatch_barrier_async的不等待(異步)特性體現(xiàn)在將任務(wù)插入隊(duì)列的過程鱼炒,它的等待特性體現(xiàn)在任務(wù)真正執(zhí)行的過程。
(9).GCD調(diào)度組
使用場(chǎng)景:在實(shí)際開發(fā)中蝌借,需要開啟N個(gè)異步線程昔瞧,但是后續(xù)操作,需要依賴N個(gè)線程返回的數(shù)據(jù)菩佑,需要接收所有線程任務(wù)執(zhí)行完成的通知自晰。
例:
#pragma mark - 調(diào)度組
- (void)group{
/*
*應(yīng)用場(chǎng)景:
開發(fā)的時(shí)候,有時(shí)候出現(xiàn)多個(gè)網(wǎng)絡(luò)請(qǐng)求都完成以后(每個(gè)網(wǎng)絡(luò)請(qǐng)求時(shí)間的時(shí)長(zhǎng)不一樣)稍坯,再通知用戶
比如下載書:三國(guó)演義酬荞,紅樓夢(mèng)搓劫,西游記
*/
????????? //1.實(shí)例化一個(gè)調(diào)度組
??????? dispatch_group_t group = dispatch_group_create();
?????? //2.隊(duì)列
?????? dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
????? //3.任務(wù)添加到隊(duì)列queue
???? dispatch_group_async(group,? queue, ^{
????? ?? ? for (int i = 0; i<=50; i++) {
????????????????? if (i == 50) {
????????????????????? NSLog(@"---下載小說A:%@",[NSThread currentThread]);
????????????????? }
????????? }
?? });
? dispatch_group_async(group,? queue, ^{
???????? for (int i = 0; i<=50; i++) {
??????????????? if (i == 50) {
??????????????????? NSLog(@"---下載小說B:%@",[NSThread currentThread]);
????????????? }
??? }
});
dispatch_group_async(group,? queue, ^{
???????? for (int i = 0; i<=500; i++) {
?????????????? if (i == 50) {
??????????????????? NSLog(@"---下載小說C:%@",[NSThread currentThread]);
???????????? }
??????? }
});
//4.獲得所有調(diào)度組里面的異步任務(wù)完成的通知<上面3本書都下載完了才會(huì)執(zhí)行>
??? dispatch_group_notify(group, queue, ^{
?????????? NSLog(@"--- 下載完成的操作:%@",[NSThread currentThread]);
? });
}
輸出結(jié)果: