什么是GCD
GCD(Grand Central Dispatch)是異步執(zhí)行任務(wù)的技術(shù)之一鳞尔。一般將應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)級(jí)中實(shí)現(xiàn)寥假。開發(fā)者只需要定義想執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中霞扬,GCD就能生成必要的線程并計(jì)劃執(zhí)行任務(wù)。由于線程管理是作為系統(tǒng)的一部分來實(shí)現(xiàn)的喻圃,因此可統(tǒng)一管理,也可執(zhí)行任務(wù)斧拍,這樣就比以前的線程具有更高的效率。
dispatch_async(queue, ^{
/*
長時(shí)間處理的任務(wù)愚墓,如圖像識(shí)別昂勉,數(shù)據(jù)庫訪問
*/
//長時(shí)間處理結(jié)束,主線程使用該處理結(jié)果
dispatch_async(dispatch_get_main_queue(), ^{
//只在主線程中執(zhí)行的操作岗照,如更新用戶界面
});
}
);
使用
NSObject performSelectorInBackground:(nonnull SEL) withObject:(nullable id)
實(shí)現(xiàn)前面的GCD
/*
NSObject performSelectorInBackground:(nonnull SEL) withObject:(nullable id)方法中執(zhí)行后臺(tái)線程
*/
- (void)launchThreadByNSObject_performSelectorInBackground_withObject{
[self performSelectorInBackground:@selector(doWork) withObject:nil];
}
/*
后臺(tái)執(zhí)行方法
*/
- (void)doWork{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
/*
長時(shí)間處理的任務(wù),如圖像識(shí)別煞肾,數(shù)據(jù)庫訪問
*/
//長時(shí)間處理結(jié)束嗓袱,主線程使用該處理結(jié)果
[self performSelectorOnMainThread:@selector(doneWork) withObject:nil waitUntilDone:NO];
[pool drain];
}
//主線程處理方法
- (void)doneWork{
//只在主線程中執(zhí)行的操作,如更新用戶界面
}
GCD除了代碼簡潔蝙昙,更重要的是GCD提供系統(tǒng)級(jí)線程管理提高執(zhí)行效率。
多線程編程
OC中代碼基本上都是從上到下的順序執(zhí)行奇颠。
if語句和for語句等控制語句或函數(shù)調(diào)用的情況下放航,執(zhí)行命令列的地址會(huì)遠(yuǎn)離當(dāng)前位置,但是,由于一個(gè)CPU一次只能執(zhí)行一個(gè)命令吓妆,不能執(zhí)行某處分開的并列的兩個(gè)命令吨铸,因此,通過CPU執(zhí)行的CPU命令好比一條無分叉的大道诞吱,其執(zhí)行不會(huì)出現(xiàn)分歧。如圖:
這里所說的1個(gè)cpu執(zhí)行的cpu命令列為一條無分叉路經(jīng)就是線程≌犹保現(xiàn)在一個(gè)物理的cpu芯片實(shí)際上有64個(gè)cpu(64核)握巢,如果一個(gè)cpu核虛擬兩個(gè)cpu核工作,那么一臺(tái)計(jì)算機(jī)上使用多個(gè)cpu核就是理所當(dāng)然的事情了暴浦。這種無分叉的路徑不止一條,存在多條時(shí)即為多線程飞几。
OSX和iOS的核心XNU內(nèi)核在發(fā)生操作系統(tǒng)事件時(shí)會(huì)切換執(zhí)行路徑独撇。執(zhí)行中路徑的狀態(tài),例如CPU的寄存器等信息保存到各自路徑專用的內(nèi)存塊中卵史,從切換目標(biāo)路徑專用的內(nèi)存塊中,復(fù)原CPU寄存器等信息以躯,繼續(xù)執(zhí)行切換路徑的CPU命令列啄踊,這稱為上下文切換。
由于使用多線程的程序可以在某個(gè)線程和其他線程之間反復(fù)多次進(jìn)行上下文切換颠通,因此看上去好像一個(gè)cpu核能執(zhí)行多個(gè)線程一樣,在具有多個(gè)核的cpu核的情況下就不是看上去了顿锰,而是真正的多線程技術(shù)了启搂。
多線程編程容易引發(fā)多種錯(cuò)誤狐血,比如多個(gè)線程更新相同的資源會(huì)導(dǎo)致數(shù)據(jù)不一致,停止等待事件的線程會(huì)導(dǎo)致多個(gè)線程相互持續(xù)等待,使用太多線程會(huì)消耗大量內(nèi)存等浪默。但是使用多線程能保證程序等響應(yīng)性能。
應(yīng)用程序在啟動(dòng)時(shí)碰逸,通過最先執(zhí)行等線程,即饵史,主線程來描繪用戶界面胜榔,處理觸摸屏幕等事件等。如果在該主線程中進(jìn)行長時(shí)間的處理夭织,如AR用畫像的識(shí)別和數(shù)據(jù)庫訪問,就會(huì)妨礙主線程的執(zhí)行讲竿,在OSX和iOS的應(yīng)用程序中,會(huì)妨礙主線程中唄稱為RunLoop的主循環(huán)的執(zhí)行题禀,從而導(dǎo)致不能更新用戶界面膀捷,應(yīng)用程序的畫面長時(shí)間停滯等問題。
使用多線程編程担孔,在執(zhí)行長時(shí)間的處理時(shí)仍可保證用戶界面的響應(yīng)性能。GCD大大簡化了啄育,偏于復(fù)雜的多線程編程的源代碼。