目錄:
1.進(jìn)程與線程分別是什么意思?
2.什么是多線程?
3.多線程的優(yōu)點(diǎn)和缺點(diǎn)有哪些?
4.多線程的 并行 和 并發(fā) 有什么區(qū)別?
5.iOS中實(shí)現(xiàn)多線程的幾種方案,各自有什么特點(diǎn)?
6.多個(gè)網(wǎng)絡(luò)請求完成后如何執(zhí)行下一步?
7. 多個(gè)網(wǎng)絡(luò)請求順序執(zhí)行后如何執(zhí)行下一步?
8.如何理解多線程中的死鎖?
9.如何去理解GCD執(zhí)行原理?
1.進(jìn)程與線程分別是什么意思?
進(jìn)程:
1.進(jìn)程是一個(gè)具有一定獨(dú)立功能的程序關(guān)于某次數(shù)據(jù)集合的一次運(yùn)行活動(dòng),它是操作系統(tǒng)分配資源的基本單元.
2.進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,就是一段程序的執(zhí)行過程,我們可以理解為手機(jī)上的一個(gè)app.
3.每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空間內(nèi),擁有獨(dú)立運(yùn)行所需的全部資源
線程
1.程序執(zhí)行流的最小單元,線程是進(jìn)程中的一個(gè)實(shí)體.
2.一個(gè)進(jìn)程要想執(zhí)行任務(wù),必須至少有一條線程.應(yīng)用程序啟動(dòng)的時(shí)候,系統(tǒng)會(huì)默認(rèn)開啟一條線程,也就是主線程
進(jìn)程和線程的關(guān)系
1.線程是進(jìn)程的執(zhí)行單元,進(jìn)程的所有任務(wù)都在線程中執(zhí)行
2.線程是 CPU 分配資源和調(diào)度的最小單位
3.一個(gè)程序可以對應(yīng)多個(gè)進(jìn)程(多進(jìn)程),一個(gè)進(jìn)程中可有多個(gè)線程,但至少要有一條線程
4.同一個(gè)進(jìn)程內(nèi)的線程共享進(jìn)程資源
2.什么是多線程?
多線程的實(shí)現(xiàn)原理:事實(shí)上,同一時(shí)間內(nèi)單核的CPU只能執(zhí)行一個(gè)線程,多線程是CPU快速的在多個(gè)線程之間進(jìn)行切換(調(diào)度),造成了多個(gè)線程同時(shí)執(zhí)行的假象。
如果是多核CPU就真的可以同時(shí)處理多個(gè)線程了。
多線程的目的是為了同步完成多項(xiàng)任務(wù),通過提高系統(tǒng)的資源利用率來提高系統(tǒng)的效率。
3.多線程的優(yōu)點(diǎn)和缺點(diǎn)有哪些?
優(yōu)點(diǎn):
能適當(dāng)提高程序的執(zhí)行效率
能適當(dāng)提高資源利用率(CPU、內(nèi)存利用率)
缺點(diǎn):
開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,主線程占用1M,子線程占用512KB),如果開啟大量的線程,會(huì)占用大量的內(nèi)存空間,降低程序的性能
線程越多,CPU在調(diào)度線程上的開銷就越大
程序設(shè)計(jì)更加復(fù)雜:比如線程之間的通信、多線程的數(shù)據(jù)共享
4.多線程的 并行 和 并發(fā) 有什么區(qū)別?
并行:充分利用計(jì)算機(jī)的多核,在多個(gè)線程上同步進(jìn)行
并發(fā):在一條線程上通過快速切換,讓人感覺在同步進(jìn)行
5.iOS中實(shí)現(xiàn)多線程的幾種方案,各自有什么特點(diǎn)?
NSThread 面向?qū)ο蟮模枰绦騿T手動(dòng)創(chuàng)建線程,但不需要手動(dòng)銷毀。子線程間通信很難。
GCD c語言,充分利用了設(shè)備的多核,自動(dòng)管理線程生命周期。比NSOperation效率更高。
NSOperation 基于gcd封裝,更加面向?qū)ο螅萭cd多了一些功能。
6.多個(gè)網(wǎng)絡(luò)請求完成后如何執(zhí)行下一步?
使用GCD的dispatch_group_t
創(chuàng)建一個(gè)dispatch_group_t
每次網(wǎng)絡(luò)請求前先dispatch_group_enter,請求回調(diào)后再dispatch_group_leave,enter和leave必須配合使用,有幾次enter就要有幾次leave,否則group會(huì)一直存在。
當(dāng)所有enter的block都leave后,會(huì)執(zhí)行dispatch_group_notify的block。
NSString*str=@"http://xxxx.com/";
NSURL*url=[NSURL URLWithString:str];
NSURLRequest*request=[NSURLRequest requestWithURL:url];
NSURLSession*session=[NSURLSession sharedSession];
dispatch_group_t downloadGroup=dispatch_group_create();
for(inti=0;i<10;i++){
dispatch_group_enter(downloadGroup);
NSURLSessionDataTask*task=[session dataTaskWithRequest:request completionHandler:^(NSData*_Nullable data,NSURLResponse*_Nullable response,NSError*_Nullable error){
NSLog(@"%d---%d",i,i);
dispatch_group_leave(downloadGroup);
}];
[task resume];
}
dispatch_group_notify(downloadGroup,dispatch_get_main_queue(),^{
NSLog(@"end");
});
使用GCD的信號(hào)量dispatch_semaphore_t
dispatch_semaphore信號(hào)量為基于計(jì)數(shù)器的一種多線程同步機(jī)制。如果semaphore計(jì)數(shù)大于等于1,計(jì)數(shù)-1,返回,程序繼續(xù)運(yùn)行。如果計(jì)數(shù)為0,則等待。dispatch_semaphore_signal(semaphore)為計(jì)數(shù)+1操作,dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)為設(shè)置等待時(shí)間,這里設(shè)置的等待時(shí)間是一直等待。
創(chuàng)建semaphore為0,等待,等10個(gè)網(wǎng)絡(luò)請求都完成了,dispatch_semaphore_signal(semaphore)為計(jì)數(shù)+1,然后計(jì)數(shù)-1返回
NSString*str=@"http://xxxx.com/";
NSURL*url=[NSURL URLWithString:str];
NSURLRequest*request=[NSURLRequest requestWithURL:url];
NSURLSession*session=[NSURLSession sharedSession];
dispatch_semaphore_t sem=dispatch_semaphore_create(0);
for(inti=0;i<10;i++){
NSURLSessionDataTask*task=[session dataTaskWithRequest:request completionHandler:^(NSData*_Nullable data,NSURLResponse*_Nullable response,NSError*_Nullable error){
NSLog(@"%d---%d",i,i);
count++;
if(count==10){
dispatch_semaphore_signal(sem);
count=0;
}
}];
[task resume];
}
dispatch_semaphore_wait(sem,DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(),^{
NSLog(@"end");
});
7.多個(gè)網(wǎng)絡(luò)請求順序執(zhí)行后如何執(zhí)行下一步?
使用信號(hào)量semaphore
每一次遍歷,都讓其dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER),這個(gè)時(shí)候線程會(huì)等待,阻塞當(dāng)前線程,直到dispatch_semaphore_signal(sem)調(diào)用之后
NSString*str=@"http://www.lxweimin.com/p/6930f335adba";
NSURL*url=[NSURL URLWithString:str];
NSURLRequest*request=[NSURLRequest requestWithURL:url];
NSURLSession*session=[NSURLSession sharedSession];
dispatch_semaphore_t sem=dispatch_semaphore_create(0);
for(inti=0;i<10;i++){
NSURLSessionDataTask*task=[session dataTaskWithRequest:request completionHandler:^(NSData*_Nullable data,NSURLResponse*_Nullable response,NSError*_Nullable error){
NSLog(@"%d---%d",i,i);
dispatch_semaphore_signal(sem);
}];
[task resume];
dispatch_semaphore_wait(sem,DISPATCH_TIME_FOREVER);
}
dispatch_async(dispatch_get_main_queue(),^{
NSLog(@"end");
});
8.如何理解多線程中的死鎖?
死鎖是由于多個(gè)線程(進(jìn)程)在執(zhí)行過程中,因?yàn)闋帄Z資源而造成的互相等待現(xiàn)象,你可以理解為卡主了。產(chǎn)生死鎖的必要條件有四個(gè):
互斥條件 :指進(jìn)程對所分配到的資源進(jìn)行排它性使用,即在一段時(shí)間內(nèi)某資源只由一個(gè)進(jìn)程占用。如果此時(shí)還有其它進(jìn)程請求資源,則請求者只能等待,直至占有資源的進(jìn)程用畢釋放。
請求和保持條件 :指進(jìn)程已經(jīng)保持至少一個(gè)資源,但又提出了新的資源請求,而該資源已被其它進(jìn)程占有,此時(shí)請求進(jìn)程阻塞,但又對自己已獲得的其它資源保持不放。
不可剝奪條件 :指進(jìn)程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時(shí)由自己釋放。
環(huán)路等待條件 :指在發(fā)生死鎖時(shí),必然存在一個(gè)進(jìn)程——資源的環(huán)形鏈,即進(jìn)程集合{P0,P1,P2,···,Pn}中的P0正在等待一個(gè)P1占用的資源;P1正在等待P2占用的資源,……,Pn正在等待已被P0占用的資源。
最常見的就是 同步函數(shù) + 主隊(duì)列 的組合,本質(zhì)是隊(duì)列阻塞。
dispatch_sync(dispatch_get_main_queue(),^{
NSLog(@"2");
});
NSLog(@"1");
// 什么也不會(huì)打印,直接報(bào)錯(cuò)
9.如何去理解GCD執(zhí)行原理?
GCD有一個(gè)底層線程池,這個(gè)池中存放的是一個(gè)個(gè)的線程。之所以稱為“池”,很容易理解出這個(gè)“池”中的線程是可以重用的,當(dāng)一段時(shí)間后這個(gè)線程沒有被調(diào)用胡話,這個(gè)線程就會(huì)被銷毀。注意:開多少條線程是由底層線程池決定的(線程建議控制再3~5條),池是系統(tǒng)自動(dòng)來維護(hù),不需要我們程序員來維護(hù)(看到這句話是不是很開心?) 而我們程序員需要關(guān)心的是什么呢?我們只關(guān)心的是向隊(duì)列中添加任務(wù),隊(duì)列調(diào)度即可。
如果隊(duì)列中存放的是同步任務(wù),則任務(wù)出隊(duì)后,底層線程池中會(huì)提供一條線程供這個(gè)任務(wù)執(zhí)行,任務(wù)執(zhí)行完畢后這條線程再回到線程池。這樣隊(duì)列中的任務(wù)反復(fù)調(diào)度,因?yàn)槭峭降模援?dāng)我們用currentThread打印的時(shí)候,就是同一條線程。
如果隊(duì)列中存放的是異步的任務(wù),(注意異步可以開線程),當(dāng)任務(wù)出隊(duì)后,底層線程池會(huì)提供一個(gè)線程供任務(wù)執(zhí)行,因?yàn)槭钱惒綀?zhí)行,隊(duì)列中的任務(wù)不需等待當(dāng)前任務(wù)執(zhí)行完畢就可以調(diào)度下一個(gè)任務(wù),這時(shí)底層線程池中會(huì)再次提供一個(gè)線程供第二個(gè)任務(wù)執(zhí)行,執(zhí)行完畢后再回到底層線程池中。
這樣就對線程完成一個(gè)復(fù)用,而不需要每一個(gè)任務(wù)執(zhí)行都開啟新的線程,也就從而節(jié)約的系統(tǒng)的開銷,提高了效率。在iOS7.0的時(shí)候,使用GCD系統(tǒng)通常只能開58條線程,iOS8.0以后,系統(tǒng)可以開啟很多條線程,但是實(shí)在開發(fā)應(yīng)用中,建議開啟線程條數(shù):35條最為合理。