GCD是什么:一句話負(fù)責(zé)線程池的中央調(diào)度
GCD全稱為Grand Central Dispatch顶滩,是libdispatch的市場(chǎng)名稱,而libdispatch是Apple的一個(gè)庫(kù),其為并發(fā)代碼在iOS和OS X的多核硬件上執(zhí)行提供支持。確切地說(shuō)GCD是一套低層級(jí)的C API,通過(guò) GCD屯伞,開(kāi)發(fā)者只需要向隊(duì)列中添加一段代碼塊(block或C函數(shù)指針),而不需要直接和線程打交道蝌数。GCD在后端管理著一個(gè)線程池愕掏,它不僅決定著你的代碼塊將在哪個(gè)線程被執(zhí)行,還根據(jù)可用的系統(tǒng)資源對(duì)這些線程進(jìn)行管理顶伞。這樣通過(guò)GCD來(lái)管理線程饵撑,從而解決線程被創(chuàng)建的問(wèn)題。
GCD的優(yōu)勢(shì)
- 易用: GCD 提供一個(gè)易于使用的并發(fā)模型而不僅僅只是鎖和線程唆貌,以幫助我們避開(kāi)并發(fā)陷阱,而且因?yàn)榛赽lock滑潘,它能極為簡(jiǎn)單得在不同代碼作用域之間傳遞上下文。
- 靈活: GCD 具有在常見(jiàn)模式上(比如鎖锨咙、單例)语卤,用更高性能的方法優(yōu)化代碼,而且GCD能提供更多的控制權(quán)力以及大量的底層函數(shù)酪刀。
- 性能: GCD能自動(dòng)根據(jù)系統(tǒng)負(fù)載來(lái)增減線程數(shù)量粹舵,這就減少了上下文切換以及增加了計(jì)算效率。
相關(guān)概念
GCD中涉及到隊(duì)列骂倘、線程眼滤、串行并行、同步異步历涝、串行并發(fā)等概念诅需,這些概念的認(rèn)知可以通過(guò)我的另一篇文章
Dispatch Objects
盡管GCD是純C語(yǔ)言的,但它被組建成面向?qū)ο蟮娘L(fēng)格荧库。GCD對(duì)象被稱為dispatch object, 所有的dispatch objects都是OC對(duì)象.堰塌,就如其他OC對(duì)象一樣,當(dāng)開(kāi)啟了ARC(automatic reference counting)時(shí),dispatch objects的retain和release都會(huì)自動(dòng)執(zhí)行分衫。而如果是MRC的話场刑,dispatch objects會(huì)使用dispatch_retain和dispatch_release這兩個(gè)方法來(lái)控制引用計(jì)數(shù)。Serial & Concurrent
串行任務(wù)就是每次只有一個(gè)任務(wù)被執(zhí)行丐箩,并發(fā)任務(wù)就是在同一時(shí)間可以有多個(gè)任務(wù)被執(zhí)行摇邦。Synchronous & Asynchronous
同步函數(shù)意思是在完成了它預(yù)定的任務(wù)后才返回恤煞,在任務(wù)執(zhí)行時(shí)會(huì)阻塞當(dāng)前線程屎勘。而異步函數(shù)則是任務(wù)會(huì)完成但不會(huì)等它完成施籍,所以異步函數(shù)不會(huì)阻塞當(dāng)前線程,會(huì)繼續(xù)去執(zhí)行下一個(gè)函數(shù)概漱。Concurrency & Parallelism
并發(fā)的意思就是同時(shí)運(yùn)行多個(gè)任務(wù)丑慎。這些任務(wù)可能是以在單核 CPU 上以分時(shí)(時(shí)間共享)的形式同時(shí)運(yùn)行,也可能是在多核 CPU 上以真正的并行方式來(lái)運(yùn)行瓤摧。然后為了使單核設(shè)備也能實(shí)現(xiàn)這一點(diǎn)竿裂,并發(fā)任務(wù)必須先運(yùn)行一個(gè)線程,執(zhí)行一個(gè)上下文切換照弥,然后運(yùn)行另一個(gè)線程或進(jìn)程腻异。并行則是真正意思上的多任務(wù)同時(shí)運(yùn)行。Context Switch
Context Switch即上下文切換这揣,一個(gè)上下文切換指當(dāng)你在單個(gè)進(jìn)程里切換執(zhí)行不同的線程時(shí)存儲(chǔ)與恢復(fù)執(zhí)行狀態(tài)的過(guò)程悔常。這個(gè)過(guò)程在編寫(xiě)多任務(wù)應(yīng)用時(shí)很普遍,但會(huì)帶來(lái)一些額外的開(kāi)銷给赞。Dispatch Queues
GCD dispatch queues是一個(gè)強(qiáng)大的執(zhí)行多任務(wù)的工具机打。Dispatch queue是一個(gè)對(duì)象,它可以接受任務(wù)片迅,并將任務(wù)以先進(jìn)先出(FIFO)的順序來(lái)執(zhí)行残邀。Dispatch queue可以并發(fā)的或串行的執(zhí)行任意一個(gè)代碼塊,而且并發(fā)任務(wù)會(huì)像NSOperationQueue那樣基于系統(tǒng)負(fù)載來(lái)合適地并發(fā)進(jìn)行柑蛇,串行隊(duì)列同一時(shí)間則只執(zhí)行單一任務(wù)芥挣。Dispatch queues內(nèi)部使用的是線程,GCD 管理這些線程耻台,并且使用Dispatch queues的時(shí)候空免,我們都不需要自己創(chuàng)建線程。Dispatch queues相對(duì)于和線程直接通信的代碼優(yōu)勢(shì)是:Dispatch queues使用起來(lái)特別方便粘我,執(zhí)行任務(wù)更加有效率鼓蜒。
具體使用
隊(duì)列
對(duì)了除了串行和并行之分,全局隊(duì)列還有一些相關(guān)屬性影響著隊(duì)列內(nèi)任務(wù)的執(zhí)行征字,比如優(yōu)先級(jí)等都弹,高優(yōu)先級(jí)的隊(duì)列,在等候被調(diào)度的情況下更容易獲取資源或機(jī)會(huì)
- 串行隊(duì)列
//主隊(duì)列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//自定義的串行隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue0", DISPATCH_QUEUE_SERIAL);
- 并行隊(duì)列
//系統(tǒng)的全局并行隊(duì)列
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
//自定義的并行隊(duì)列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
- 串行并行的參數(shù)
DISPATCH_QUEUE_SERIAL //串行
DISPATCH_QUEUE_CONCURREN //并行
- 全局隊(duì)列的優(yōu)先級(jí)匙姜,默認(rèn)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
任務(wù)
- 同步任務(wù)
dispatch_sync(globalQueue, ^{
//同步任務(wù)
});
- 異步任務(wù)
dispatch_async(globalQueue, ^{
//異步任務(wù)
});
- dispatch_suspend != 立即停止隊(duì)列的運(yùn)行
dispatch_suspend畅厢,dispatch_resume提供了“掛起、恢復(fù)”隊(duì)列的功能氮昧,簡(jiǎn)單來(lái)說(shuō)框杜,就是可以暫停浦楣、恢復(fù)隊(duì)列上的任務(wù)。但是dispatch_suspend并不會(huì)立即暫停正在運(yùn)行的block咪辱,而是在當(dāng)前block執(zhí)行完成后振劳,暫停后續(xù)的block執(zhí)行
其他使用
- DispatchGroup 任務(wù)組
很多時(shí)候我們需要等待一系列任務(wù)(block)執(zhí)行完成,然后再做一些收尾的工作油狂。如果是有序的任務(wù)历恐,可以分步驟完成的,直接使用串行隊(duì)列就行专筷。但是如果是一系列并行執(zhí)行的任務(wù)弱贼,就需要DispatchGroup 任務(wù)組了
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, globalQueue, ^{
//A
});
dispatch_group_async(group, globalQueue, ^{
//B
});
//當(dāng)此group,此隊(duì)列中的所有任務(wù)都結(jié)束才執(zhí)行此block
dispatch_group_notify(group, globalQueue, ^{
});
- dispatch_group_enter(group)磷蛹、dispatch_group_leave(group)
DispatchGroup 任務(wù)組的并發(fā)任務(wù)的情況吮旅,如果此時(shí)拿不到隊(duì)列對(duì)象就沒(méi)法使用dispatch_group_async(group,隊(duì)列),怎么辦呢
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//Enter group
dispatch_group_enter(group);
[manager GET:@"http://www.baidu.com" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
//Deal with result...
//Leave group
dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//Deal with error...
//Leave group
dispatch_group_leave(group);
}];
加結(jié)束任務(wù)
添加結(jié)束任務(wù)也可以分為兩種情況味咳,如下:
在當(dāng)前線程阻塞的同步等待: dispatch_group_wait(<#dispatch_group_t _Nonnull group#>, <#dispatch_time_t timeout#>)庇勃。
添加一個(gè)異步執(zhí)行的任務(wù)作為結(jié)束任務(wù):dispatch_group_notify(group, globalQueue, ^{
});dispatch_barrier_async
同一個(gè)隊(duì)列,dispatch_barrier_async添加的任務(wù)會(huì)阻塞后面的任務(wù)莺葫,直至此任務(wù)執(zhí)行結(jié)束匪凉;注意:只在自己創(chuàng)建的并發(fā)隊(duì)列上有效
dispatch_barrier_async(concurrentQueue, ^{
for (int i=0; i<5; i++) {
NSLog(@"=%@=====%d",[NSThread currentThread],i);
}
});
dispatch_async(concurrentQueue, ^{
for (int i=5; i<10; i++) {
NSLog(@"=%@=====%d",[NSThread currentThread],i);
}
});
- 延時(shí)執(zhí)行 dispatch_after
//主隊(duì)列中的延時(shí)執(zhí)行 時(shí)間單位是dispatch_time_t
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
//任意隊(duì)列中的延時(shí)執(zhí)行
dispatch_after(DISPATCH_TIME_NOW+30, globalQueue, ^{
});
- 一次性代碼,單例常用
dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
//默認(rèn)線程安全
});
- 遍歷 讓循環(huán)并行執(zhí)行
dispatch_apply(10, globalQueue, ^(size_t index) {
//會(huì)執(zhí)行10次 index順序不確定
});