問題思考
- 什么是進(jìn)程、線程铲汪?線程和進(jìn)程的關(guān)系是什么掌腰?
- 線程和隊(duì)列的關(guān)系齿梁?
- 隊(duì)列有幾種勺择?
- 什么是同步、異步稿辙?什么是串行邻储、并行旧噪?
- 并行和并發(fā)有什么區(qū)別淘钟?
看過這篇文章米母,這些有問題應(yīng)該就都有答案了铁瞒。
總是容易混淆這些概念,整理并記錄一下
目錄
1.先說幾個(gè)概念
2.隊(duì)列
串行燎斩、并發(fā)
先說幾個(gè)概念
- 進(jìn)程
- 線程
- 多線程
- 主線程
進(jìn)程
:在內(nèi)存中正在運(yùn)行的程序就是進(jìn)程,進(jìn)程是系統(tǒng)進(jìn)行資源調(diào)度分配的一個(gè)獨(dú)立單位蜂绎,進(jìn)程有獨(dú)立性栅表、并發(fā)性、動(dòng)態(tài)性师枣。
線程
: 線程是進(jìn)程的執(zhí)行單元
怪瓶,是一個(gè)獨(dú)立的、并發(fā)的順序執(zhí)行流践美,進(jìn)程所有的任務(wù)都在線程中執(zhí)行洗贰。
多線程
: 在一個(gè)進(jìn)程中可以開辟多條線程,多條線程可以并發(fā)執(zhí)行不同的任務(wù)陨倡,多條線程并發(fā)執(zhí)行,其實(shí)是CPU 快速的在多條線程之間調(diào)度兴革,CPU 的執(zhí)行很快绎晃,調(diào)度的時(shí)間足夠快就會(huì)造成多線程同時(shí)執(zhí)行的假象。
主線程
: 一個(gè)iOS 程序運(yùn)行后杂曲,會(huì)默認(rèn)開啟一個(gè)線程庶艾,這個(gè)線程就是主線程,也叫UI線程
作用
:
- 他可以通過RunLoop 來待續(xù)運(yùn)行和有事件觸發(fā)時(shí)及時(shí)喚醒響應(yīng)擎勘,沒有事件時(shí)就睡眠
- 顯示/刷新UI界面
- 處理UI事件
進(jìn)程和線程的關(guān)系 :線程是進(jìn)程的執(zhí)行單元咱揍,在進(jìn)程中開辟的獨(dú)立、并發(fā)的順序執(zhí)行流棚饵,進(jìn)程所有的任務(wù)都在線程中執(zhí)行煤裙。
隊(duì)列
FIFO
(先進(jìn)先出),是一種數(shù)據(jù)結(jié)構(gòu)蟹地,用來存放任務(wù)
- 隊(duì)列負(fù)責(zé)存放任務(wù)积暖、調(diào)度任務(wù),交給線程去執(zhí)行
- 遵循
FIFO
(先進(jìn)先出)原則怪与,是指先調(diào)度夺刑,而不是先調(diào)度完成
串行、并發(fā)
串行和并發(fā)是指隊(duì)列
的兩種類型分别。決定了任務(wù)的執(zhí)行順序
*串行隊(duì)列
遍愿,一次只能執(zhí)行一個(gè)任務(wù),上一個(gè)任務(wù)處理完成才能處理下一個(gè)任務(wù)耘斩;
*并發(fā)隊(duì)列
沼填,多個(gè)任務(wù)可以同時(shí)執(zhí)行;處理順序還是先進(jìn)先出原則括授,但任務(wù)處理時(shí)間不同坞笙,有可能先進(jìn)后調(diào)度完成
并發(fā)在實(shí)際上岩饼,是處理器一下子處理任務(wù)A ,一下子處理任務(wù)B 薛夜,看起來就像同時(shí)在執(zhí)行多個(gè)任務(wù)
并行
并行和并發(fā)很容易讓人混淆
并行
和并發(fā)
的效果在用戶看來是一樣的籍茧,但是其根本區(qū)別是有幾個(gè)CPU 在處理任務(wù)
-
并行
是真的有多個(gè)CPU 同時(shí)處理任務(wù)(多個(gè)線程在不同核上跑) -
并發(fā)
是只有一個(gè)CPU ,單核高頻切換任務(wù)梯澜,使用戶覺得多個(gè)任務(wù)同時(shí)執(zhí)行 -
并行
是同一時(shí)間執(zhí)行多個(gè)任務(wù) -
并發(fā)
是同一一時(shí)間間隔寞冯,執(zhí)行多個(gè)任務(wù)
任務(wù)
- 任務(wù)就是
線程
要執(zhí)行的代碼 - 執(zhí)行任務(wù)有兩種方式,
同步
和異步
同步晚伙、異步
- 同步和異步代表任務(wù)的
執(zhí)行方式
-
同步執(zhí)行
:當(dāng)前所在隊(duì)列會(huì)阻塞住吮龄,等待該任務(wù)執(zhí)行完成后恢復(fù);
PS:這里涉及到兩個(gè)隊(duì)列咆疗,一個(gè)是當(dāng)前隊(duì)列漓帚,一個(gè)是任務(wù)所在隊(duì)列
同步執(zhí)行會(huì)阻塞當(dāng)前隊(duì)列,同步執(zhí)行的任務(wù)完成之后午磁,當(dāng)前隊(duì)列才會(huì)恢復(fù)胰默。如果當(dāng)前隊(duì)列和任務(wù)所在隊(duì)列是同一個(gè),則會(huì)循環(huán)等待漓踢,造成死鎖牵署。 -
異步執(zhí)行
:當(dāng)前隊(duì)列不會(huì)阻塞,正常執(zhí)行任務(wù)
同步不會(huì)開辟新的線程喧半,異步可以開辟新的線程(不一定會(huì)開辟新線程)
串行/并發(fā)/同步/異步
串行隊(duì)列 | 并發(fā)隊(duì)列 | |
---|---|---|
同步執(zhí)行 | 串行執(zhí)行任務(wù) | 串行執(zhí)行任務(wù) |
異步執(zhí)行 | 串行執(zhí)行任務(wù) | 并發(fā)執(zhí)行任務(wù) |
- 串行隊(duì)列奴迅,同步執(zhí)行
在當(dāng)前線程執(zhí)行,(不開啟新線程)并按順序一個(gè)一個(gè)執(zhí)行 - 串行隊(duì)列挺据,異步執(zhí)行
線程由系統(tǒng)調(diào)度取具,(不一定會(huì)開啟新線程)按順序執(zhí)行 - 并發(fā)隊(duì)列,同步執(zhí)行
在當(dāng)前線程執(zhí)行扁耐,(不開啟新線程)并按順序一個(gè)一個(gè)執(zhí)行 暇检;與串行、同步效果一樣 - 并發(fā)隊(duì)列婉称,異步執(zhí)行
系統(tǒng)可以開啟新線程块仆,執(zhí)行順序不確定
主隊(duì)列
-
主隊(duì)列
的任務(wù)會(huì)在主線程
執(zhí)行,主隊(duì)列是串行
隊(duì)列王暗。 - 在程序啟動(dòng)之后就已經(jīng)存在主線程和主隊(duì)列悔据,主隊(duì)列無需手動(dòng)創(chuàng)建,直接獲取俗壹。
- 主隊(duì)列科汗,異步執(zhí)行
NSLog(@"1");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
結(jié)果:打印132。
解析:主線程異步執(zhí)行代碼绷雏,在主隊(duì)列里的任務(wù)執(zhí)行完成時(shí)头滔,該任務(wù)才會(huì)加到主隊(duì)列里怖亭,并執(zhí)行。
所以坤检,異步執(zhí)行不是一定會(huì)開啟線程依许。在主線程異步執(zhí)行主隊(duì)列任務(wù)時(shí),就不會(huì)開啟新線程缀蹄。
- 主隊(duì)列,同步執(zhí)行
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
結(jié)果:死鎖膘婶,系統(tǒng)崩潰
執(zhí)行順序 —————————————————-------———————>
主隊(duì)列: 任務(wù)1 | 同步任務(wù)塊 | 任務(wù)3 |
????
|把任務(wù)2加到主隊(duì)列執(zhí)行|
解析:在主隊(duì)列里添加同步執(zhí)行的任務(wù)
由于是同步執(zhí)行缺前,在執(zhí)行同步任務(wù)時(shí),會(huì)阻塞當(dāng)前隊(duì)列悬襟。
該同步任務(wù)塊是把任務(wù)2添加到主隊(duì)列里執(zhí)行
而主隊(duì)列已經(jīng)被阻塞住 衅码,需要完成同步任務(wù)之后才會(huì)恢復(fù)。
所以循環(huán)等待導(dǎo)致死鎖脊岳,程序崩潰
全局隊(duì)列
-
全局隊(duì)列
本質(zhì)上是并發(fā)
隊(duì)列逝段,是系統(tǒng)提供的開發(fā)者直接使用的并發(fā)隊(duì)列
代碼題
用幾個(gè)代碼題加深理解
- 輸出什么?
1.1 隊(duì)列換成串行隊(duì)列呢割捅?
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
NSLog(@"2");
});
NSLog(@"%@", [NSThread currentThread]);
NSLog(@"3");
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
NSLog(@"4");
});
NSLog(@"5");
});
NSLog(@"6");
1) 打印162354 奶躯,線程打印不一定,因?yàn)槭遣l(fā)隊(duì)列
1.1) 打印16亿驾, 崩潰 嘹黔。串行隊(duì)列,同步執(zhí)行任務(wù)莫瞬,相互等待死鎖
- 打印順序
2.1 改為串行隊(duì)列呢儡蔓?
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
});
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"0");
dispatch_async(queue, ^{
NSLog(@"4");
});
dispatch_async(queue, ^{
NSLog(@"7");
});
dispatch_async(queue, ^{
NSLog(@"8");
});
dispatch_async(queue, ^{
NSLog(@"9");
});
2)答 :1,2,4,7,8,9 由于是異步執(zhí)行,開啟新線程疼邀,所以順序不能確定; 3 是同步執(zhí)行喂江,與0 同在主線程,所以3在0前面旁振; 主線程任務(wù)是順序添加的获询,所以0在789 前面
2.1)順序打印1230789
- 輸出什么
3.1 塊任務(wù)中NSLog(@"3")
;,改為同步任務(wù)拐袜,輸出什么
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_async(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
dispatch_sync(queue, ^{
NSLog(@"5");
});
3)15243
3.1)15234
- 輸出什么
4.1 如果把全局并發(fā)隊(duì)列換成 創(chuàng)建的queue 怎么打印
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(dispatch_get_global_queue(0,0), ^{
NSLog(@"3");
});
NSLog(@"4");
});
dispatch_sync(queue, ^{
NSLog(@"5");
});
4)15234
4.1)152崩潰