最近準(zhǔn)備找工作, 所以又把多線(xiàn)程的知識(shí)再學(xué)習(xí)總結(jié)一遍, 讓自己更好的熟悉和運(yùn)用 iOS 多線(xiàn)程的相關(guān)操作.
進(jìn)程
- 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序
- 每個(gè)進(jìn)程之間是相互獨(dú)立的, 每個(gè)進(jìn)程均運(yùn)行在其專(zhuān)用且受保護(hù)的內(nèi)存空間內(nèi)
(可以在 Mac 的活動(dòng)指示器查看當(dāng)前系統(tǒng)內(nèi)運(yùn)行的進(jìn)程)
線(xiàn)程
- 一個(gè)進(jìn)程要想執(zhí)行任務(wù),必須要有線(xiàn)程,至少有一條線(xiàn)程
- 一個(gè)進(jìn)程的所有任務(wù)都是在線(xiàn)程中執(zhí)行
線(xiàn)程的串行
一個(gè)線(xiàn)程中任務(wù)的執(zhí)行是串行的, 也就是說(shuō)同一時(shí)間內(nèi)一個(gè)線(xiàn)程只能執(zhí)行一個(gè)任務(wù)
進(jìn)程和線(xiàn)程的比較
- 線(xiàn)程是 CPU 調(diào)用的最小單位
- 進(jìn)程是 CPU 分配資源和調(diào)度的單位
- 一個(gè)程序可以對(duì)應(yīng)過(guò)個(gè)進(jìn)程,一個(gè)進(jìn)程中可有多個(gè)線(xiàn)程,但至少要有一條線(xiàn)程
- 同一個(gè)進(jìn)程內(nèi)的線(xiàn)程共享進(jìn)程資源
多線(xiàn)程
一個(gè)進(jìn)程可以開(kāi)啟多條線(xiàn)程,每條線(xiàn)程可以并行執(zhí)行不同的任務(wù). 這個(gè)技術(shù)可以提高程序的執(zhí)行效率
多線(xiàn)程原理
- 同一時(shí)間,CPU 只能處理一條線(xiàn)程, 只有一條線(xiàn)程在工作
- 多線(xiàn)程并發(fā)執(zhí)行,其實(shí)是 CPU 快速的在多條線(xiàn)程之間調(diào)度(切換)
- 如果 CPU 調(diào)度線(xiàn)程的時(shí)間足夠快, 就造成了多線(xiàn)程并發(fā)執(zhí)行的假象
多線(xiàn)程的優(yōu)點(diǎn)和缺點(diǎn)
優(yōu)點(diǎn)
- 能適當(dāng)?shù)奶岣叱绦虻膱?zhí)行效率
- 能適當(dāng)提高資源利用率(CPU 內(nèi)存利用率)
缺點(diǎn)
- 創(chuàng)建多線(xiàn)程是有開(kāi)銷(xiāo)的,iOS 下主要成本包括: 內(nèi)核數(shù)據(jù)結(jié)構(gòu),(大約1KB), 棧空間(子線(xiàn)程512KB, 主線(xiàn)程1MB, 也可以使用 -setStackSize: 設(shè)置, 但必須是4K 的倍數(shù), 而且最小是16K), 創(chuàng)建線(xiàn)程大約需要90毫秒的創(chuàng)建時(shí)間
- 如果開(kāi)啟大量線(xiàn)程, 會(huì)降低程序的性能
- 線(xiàn)程越多,CPU 在調(diào)度線(xiàn)程上的開(kāi)銷(xiāo)就越大
- 程序設(shè)計(jì)更加復(fù)雜: 比如線(xiàn)程之間的通信, 多線(xiàn)程的數(shù)據(jù)共享
多線(xiàn)程在 iOS 開(kāi)發(fā)中的應(yīng)用
主線(xiàn)程
一個(gè) iOS 程序運(yùn)行后, 默認(rèn)會(huì)開(kāi)啟一條線(xiàn)程, 成為"主線(xiàn)程"或者"UI 線(xiàn)程"
主線(xiàn)程的主要作用
- 顯示/刷新 UI 界面
- 處理 UI 事件(比如點(diǎn)擊事件, 滾動(dòng)事件, 拖拽事件)
主線(xiàn)程的注意點(diǎn)
- 不要將比較耗時(shí)的操作放到主線(xiàn)程
- 耗時(shí)操作會(huì)卡住主線(xiàn)程, 嚴(yán)重影響 UI 的流暢度, 給用戶(hù)一種 "卡"的壞體檢
獲得主線(xiàn)程
[NSThread mainThread];
獲得當(dāng)前線(xiàn)程
[NSThread currentThread];
判斷是否為主線(xiàn)程
// 類(lèi)方法
BOOL isMainA = [NSThread isMainThread];
// 對(duì)象方法
BOOL isMainB = [thread isMainThread];
返回值為1, 就是主線(xiàn)程
耗時(shí)操作演示
界面添加一個(gè)按鈕, 給按鈕添加一個(gè)事件, 通過(guò)打印當(dāng)前線(xiàn)程可是事件是在主線(xiàn)程操作的,
NSLog(@"currentThread = %@", [NSThread currentThread]);
打印信息
currentThread = <NSThread: 0x7fcd3a504ec0>{number = 1, name = main}
再給界面添加一個(gè)可以滾動(dòng)的控件,例如 textView,然后讓點(diǎn)擊事件重復(fù)很多次打印操作, (比如999999次),
for (int i = 0; i < 99999; ++i) {
NSLog(@"currentThread= %@, 已執(zhí)行次數(shù)=%d", [NSThread currentThread], i + 1);
}
這個(gè)時(shí)候發(fā)現(xiàn)再去拖拽 textView 已經(jīng)沒(méi)反應(yīng)了, 控制臺(tái)也一直在打印,下面是部分打印結(jié)果
...
2016-07-27 13:26:09.172 多線(xiàn)程[70885:788878] currentThread= <NSThread: 0x7fdfc0f03570>{number = 1, name = main}, 已執(zhí)行次數(shù)=7258
2016-07-27 13:26:09.173 多線(xiàn)程[70885:788878] currentThread= <NSThread: 0x7fdfc0f03570>{number = 1, name = main}, 已執(zhí)行次數(shù)=7259
2016-07-27 13:26:09.173 多線(xiàn)程[70885:788878] currentThread= <NSThread: 0x7fdfc0f03570>{number = 1, name = main}, 已執(zhí)行次數(shù)=7260
2016-07-27 13:26:09.173 多線(xiàn)程[70885:788878] currentThread= <NSThread: 0x7fdfc0f03570>{number = 1, name = main}, 已執(zhí)行次數(shù)=7261
...
此時(shí)說(shuō)明主線(xiàn)程已經(jīng)被堵塞了,只有在所有打印任務(wù)執(zhí)行完畢后,才能進(jìn)行其他操作
iOS 中多線(xiàn)程的實(shí)現(xiàn)方案
技術(shù)方案 | 簡(jiǎn)介 | 語(yǔ)言 | 線(xiàn)程生命周期 | 使用頻率 |
---|---|---|---|---|
pthread | 一套通用的多線(xiàn)程 API 適用于 Unix\Linux\Windows 等系統(tǒng) 跨平臺(tái)可移植 使用難度大 |
C | 程序員管理 | 幾乎不用 |
NSThread | 使用更加面向?qū)ο?br>簡(jiǎn)單易用, 可直接操作線(xiàn)程對(duì)象 | OC | 程序員管理 | 偶爾使用 |
GCD | 旨在替代 NSThread 的線(xiàn)程技術(shù) 充分利用設(shè)備的多核 |
C | 自動(dòng)管理 | 經(jīng)常使用 |
NSOperation | 基于 GCD(底層是GCD) 比GCD 多了一些更簡(jiǎn)單實(shí)用的功能 使用更加面向?qū)ο?/td> | OC | 自動(dòng)管理 | 經(jīng)常使用 |
今天就先總結(jié)這么多, 下次逐個(gè)分析多線(xiàn)程的每種實(shí)現(xiàn)方案, 因?yàn)榈谝环N pthread 幾乎不用, 就不分析了, 下篇從 NSThread 開(kāi)始.
相關(guān)文章:
iOS多線(xiàn)程實(shí)現(xiàn)方案之--NSThread
iOS多線(xiàn)程實(shí)現(xiàn)方案之--GCD