蘋果為了減少我們開發(fā)者對(duì)多線程的開發(fā)難度娇昙,提供了兩種比較牛的并發(fā)編程技術(shù)。GCD和NSOperation蹲盘,下面我們來初步的認(rèn)識(shí)一下GCD及簡單的使用。
一苍凛、認(rèn)識(shí)GCD
1.什么是GCD?
- 全稱為Grand Central Dispatch悠栓,可譯為“牛逼的中樞調(diào)度器”
- 純C語言惭适,提供了非常強(qiáng)大的函數(shù)
2.GCD的優(yōu)勢
- GCD是蘋果為了多核的并行運(yùn)算提出的解決方案
- GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核、四核凄杯、八核)
- GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程)
- 程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼
二窑多、GCD的基本概念(隊(duì)列和任務(wù))
1.GCD中有兩個(gè)核心概念
- 隊(duì)列:用來存放任務(wù)(分為:串行隊(duì)列&并發(fā)隊(duì)列&全局隊(duì)列)
- 任務(wù):執(zhí)行什么操作(分為:同步執(zhí)行&異步執(zhí)行)
2.GCD的使用步驟就兩個(gè)
- 定制任務(wù)(做你想做的事,任你YY)
- 將任務(wù)添加到隊(duì)列中(GCD會(huì)自動(dòng)將任務(wù)取出千康,放到對(duì)應(yīng)的線程執(zhí)行值桩。取出任務(wù)的原則為FIFO:先進(jìn)先出,后進(jìn)后出)
二咳秉、簡單的使用GCD
1.GCD的創(chuàng)建方式
1.串行隊(duì)列的創(chuàng)建
//1.隊(duì)列 - 串行
/**
1.隊(duì)列名稱:
2.隊(duì)列的屬性: DISPATCH_QUEUE_SERIAL 標(biāo)示串行!
*/
dispatch_queue_t d = dispatch_queue_create("chuanxing", NULL);
串行隊(duì)列里的任務(wù)執(zhí)行方式:一個(gè)一個(gè)執(zhí)行揭芍,上一個(gè)任務(wù)執(zhí)行完了才能進(jìn)行下一個(gè)任務(wù)
2.并發(fā)隊(duì)列的創(chuàng)建
//2.隊(duì)列 - 并發(fā)
/**
1.隊(duì)列名稱:
2.隊(duì)列的屬性: DISPATCH_QUEUE_CONCURRENT 標(biāo)示并發(fā)!
*/
dispatch_queue_t d = dispatch_queue_create("bingfa", DISPATCH_QUEUE_CONCURRENT);
并行隊(duì)列里的任務(wù)執(zhí)行方式:不需要等待上一個(gè)任務(wù)執(zhí)行完靶累,就可以取出下一個(gè)任務(wù)到對(duì)應(yīng)的線程去執(zhí)行
3.同步執(zhí)行任務(wù)
//3.任務(wù) - 同步
/**
1.隊(duì)列:dispatch_queue_t
2.任務(wù):把任務(wù)放到這個(gè)隊(duì)列里去執(zhí)行
*/
dispatch_sync(d, ^{
NSLog(@"%@",[NSThread currentThread]);
});
同步執(zhí)行方式:上個(gè)任務(wù)沒執(zhí)行完庇忌,就不會(huì)執(zhí)行下個(gè)任務(wù)疏橄,同步執(zhí)行不會(huì)開啟線程
4.異步執(zhí)行任務(wù)
//3.任務(wù) - 異步
/**
1.隊(duì)列:dispatch_queue_t
2.任務(wù):把任務(wù)放到這個(gè)隊(duì)列里去執(zhí)行
*/
dispatch_async(d, ^{
NSLog(@"%@",[NSThread currentThread]);
});
異步執(zhí)行方式:上個(gè)任務(wù)沒執(zhí)行完,也會(huì)異步執(zhí)行下個(gè)任務(wù),異步執(zhí)行具備開啟線程的能力(并不是一定會(huì)開啟線程蛔翅,異步通常就是多線程的代名詞!8峭取!)
注:GCD的線程池,給不給你的任務(wù)開啟子線程,看你的任務(wù)執(zhí)行的是同步還是異步蛛砰。
同步任務(wù):不會(huì)開啟子線程去執(zhí)行任務(wù)琅翻,只會(huì)讓同步任務(wù)在當(dāng)前的線程一個(gè)一個(gè)去執(zhí)行聂抢。不管任務(wù)所在的隊(duì)列是串行的還是并發(fā)的闸拿。任務(wù)只會(huì)在當(dāng)前的線程執(zhí)行,GCD不會(huì)再為其開啟另外的線程去執(zhí)行任務(wù)但骨。
異步任務(wù):具備開啟線程的能力吼野,但不一定會(huì)開啟闷哆,要看任務(wù)所在的隊(duì)列是串行的還是并發(fā)的嘀倒。如果是串行的,任務(wù)是一個(gè)一個(gè)執(zhí)行的,即使具備開啟線程的能力,但是沒有多余的任務(wù)可以去讓GCD開啟線程贝攒。如果是并發(fā),不需要等待上一個(gè)任務(wù)執(zhí)行完咽扇,下一個(gè)任務(wù)就可以取出去執(zhí)行了,這時(shí)又具備開啟線程能力树埠,所以GCD會(huì)為這個(gè)異步任務(wù)開啟線程糠馆。
2.GCD的基本使用
1.串行隊(duì)列,同步任務(wù)
//MARK:串行隊(duì)列,同步任務(wù)
/**
* 不會(huì)開啟線程,會(huì)順序執(zhí)行
*/
-(void)GCDDemo1{
//1.隊(duì)列 - 串行
/**
1.隊(duì)列名稱:
2.隊(duì)列的屬性: DISPATCH_QUEUE_SERIAL 標(biāo)示串行!
*/
dispatch_queue_t d = dispatch_queue_create("chuanxing", NULL);
//2.同步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_sync(d, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
}
運(yùn)行結(jié)果:沒有開啟線程怎憋,按順序執(zhí)行
2.串行隊(duì)列又碌,異步任務(wù)
//MARK:串行隊(duì)列,異步任務(wù)
/**
* 會(huì)開啟子線程,按順序執(zhí)行
*/
-(void)GCDDemo1{
//1.隊(duì)列 - 串行
/**
1.隊(duì)列名稱:
2.隊(duì)列的屬性: DISPATCH_QUEUE_SERIAL 標(biāo)示串行!
*/
dispatch_queue_t d = dispatch_queue_create("chuanxing", NULL);
//2.異步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_async(d, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
}
運(yùn)行結(jié)果:開啟了子線程,按順序執(zhí)行(只會(huì)開啟一條子線程)
3.并發(fā)隊(duì)列绊袋,異步任務(wù)
//MARK:并發(fā)隊(duì)列毕匀,異步任務(wù)
/**
* 會(huì)開啟子線程,不按順序執(zhí)行
*/
-(void)GCDDemo1{
//1.隊(duì)列 - 并發(fā)
/**
1.隊(duì)列名稱:
2.隊(duì)列的屬性: DISPATCH_QUEUE_CONCURRENT 標(biāo)示并發(fā)!
*/
dispatch_queue_t d = dispatch_queue_create("bingfa", DISPATCH_QUEUE_CONCURRENT);
//2.異步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_async(d, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
}
運(yùn)行結(jié)果:開啟了子線程,不按順序執(zhí)行(任務(wù)需要多少子線程就會(huì)開啟多少子線程)每一次的運(yùn)行結(jié)果都會(huì)不一樣
4.并發(fā)隊(duì)列愤炸,同步任務(wù)
//MARK:并發(fā)隊(duì)列期揪,同步任務(wù)
/**
* 不會(huì)開啟子線程,按順序執(zhí)行
*/
-(void)GCDDemo1{
//1.隊(duì)列 - 并發(fā)
/**
1.隊(duì)列名稱:
2.隊(duì)列的屬性: DISPATCH_QUEUE_CONCURRENT 標(biāo)示并發(fā)!
*/
dispatch_queue_t d = dispatch_queue_create("bingfa", DISPATCH_QUEUE_CONCURRENT);
//2.同步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_sync(d, ^{
NSLog(@"%@ %d",[NSThread currentThread],i);
});
}
}
運(yùn)行結(jié)果:沒有開啟線程,按順序執(zhí)行
5.還有一個(gè)-->全局隊(duì)列
dispatch_queue_t d = dispatch_get_global_queue(0, 0);
全局隊(duì)列本質(zhì)上是一個(gè)并發(fā)隊(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ì)量
*/
//MARK: - 利用GCD 來做下載圖片
//異步執(zhí)行
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSURL * url = [NSURL URLWithString:@"http://img3.duitang.com/uploads/item/201604/27/20160427004300_QfKwt.jpeg"];
NSData * data = [NSData dataWithContentsOfURL:url];
UIImage * image = [UIImage imageWithData:data];
//更新UI规个,回到主隊(duì)列dispatch_get_main_queue()凤薛,這叫線程間的通訊
//這里不存在循環(huán)引用,這里的block不是屬性诞仓,不會(huì)被控制器拿到缤苫,所以不用管循環(huán)引用的問題
//主隊(duì)列是串行隊(duì)列(而且不會(huì)管你異步任務(wù)還是同步任務(wù),絕對(duì)不會(huì)開啟子線程)墅拭,所以這里用同步執(zhí)行任務(wù)和異步執(zhí)行任務(wù)都一樣
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
[self.imageView sizeToFit];
});
});
提問
問題:GCD是C語言的框架活玲,在C語言中遇到了get、new谍婉、copy舒憾、create...等等這些字樣,都需要釋放內(nèi)存穗熬《朴兀可是上面的代碼都沒有release,為什么唤蔗?
搶地主:GCD在iOS開發(fā)中太常用了探遵,ARC情況下不需要release(在MRC下,只有并發(fā)隊(duì)列才需要被release妓柜,全局隊(duì)列是不需要的)
再問:在開發(fā)過程中如何選擇隊(duì)列箱季?
我搶:
- 全局隊(duì)列,并發(fā)棍掐,能調(diào)度多個(gè)線程藏雏,執(zhí)行效率高。BUT作煌,耗電诉稍,發(fā)燙(王炸)r鸺巍!杯巨!
- 串行隊(duì)列,一個(gè)一個(gè)執(zhí)行努酸,執(zhí)行效率低(快點(diǎn)啊服爷,我等的花兒都謝了)。BUT获诈,我省電叭栽础!L蛳选笼踩!
- 可根據(jù)用戶上網(wǎng)的模式選擇:WIFI(全局隊(duì)列),流量(少開線程亡嫌,串行隊(duì)列)
小結(jié):
- 開不開線程:取決于執(zhí)行任務(wù)的函數(shù)嚎于,同步不開,異步才能開
-
開幾條線程:取決于隊(duì)列挟冠,串行開一條于购,并發(fā)開多條(異步)
注:以上幾種GCD的基本使用,可以互相套用知染,自己試試看肋僧,你會(huì)發(fā)現(xiàn)新大陸的。(同一個(gè)隊(duì)列上面的任務(wù)控淡,不一定都是一樣的嫌吠,可以是同步任務(wù)混合異步任務(wù))