關于多線程
- 概念:
- 同一個進程中同時開啟多個線程,每條線程執(zhí)行不同的任務婶溯。
- 本質:速度快
- 同一時間鲸阔,CPU只能處理一條線程,意味著只有一條線程在執(zhí)行迄委。
- CPU以人類難以察覺的速度在不同的線程之間切換褐筛,造成多條線程并發(fā)執(zhí)行的假象。
- 如果線程非常非常多叙身,CPU切換頻繁渔扎,消耗大量資源,線程執(zhí)行效率降低信轿。
- 優(yōu)點:
- 多條線程同時(并發(fā))執(zhí)行晃痴,提高程序的執(zhí)行效率。
- 提高資源利用率财忽,包括CPU倘核、內存等。
- 缺點
- 開啟新線程會占用一定內存即彪,線程過多會降低性能紧唱。
- 2.程序設計更加復雜,比如線程之間的通信隶校、多條線程的數(shù)據(jù)共享漏益。
-
附:本文目錄
iOS多線程.png
一、基本概念
- 進程
- 可以理解成一個運行中的應用程序深胳,是系統(tǒng)進行資源分配和調度的基本單位绰疤,是操作系統(tǒng)結構的基礎,主要管理資源舞终。
- 每個進程之間是獨立的峦睡,每個進程均運行在其專用且受保護的內存空間內翎苫。
- 線程
- 線程是進程的基本執(zhí)行單元,即進程想要執(zhí)行任務榨了,必須得有線程煎谍。
- 程序執(zhí)行流的最小單元,線程是進程中的一個實體龙屉。
- 同步線程
- 在當前線程內按照創(chuàng)建的先后順序依次執(zhí)行呐粘,不開啟新線程。
- 異步線程
- 在當前線程內開啟多個新的線程转捕,同時運行作岖,無先后關系。
- 隊列
- 裝載線程任務的隊形結構五芝。
- 并發(fā)
- 線程執(zhí)行可以同時一起進行執(zhí)行痘儡。
- 串行
- 線程執(zhí)行只能依次逐一先后有序的執(zhí)行。
- 線程通訊
- 在一個進程中枢步,通常有多個線程沉删,線程不是孤立存在的,線程之前需要"溝通交流"醉途。
注意點
- 一個進程可有多個線程矾瑰。
- 一個進程可有多個隊列。
- 隊列可分并發(fā)隊列和串行隊列隘擎。
二殴穴、創(chuàng)建方式
- NSThread
- 每個NSThread對象對應一個線程,真正最原始的線程货葬。
- 優(yōu)點
- NSThread 輕量級最低采幌,相對簡單。
- 可直接操作線程對象震桶。
- 缺點
- 手動管理所有的線程活動植榕,如生命周期、線程同步尼夺、睡眠等尊残。
- NSOperation
- 自帶線程管理的抽象類。
- 優(yōu)點
- 自帶線程周期管理淤堵,操作上可更注重自己邏輯寝衫。
- 缺點
- 面向對象的抽象類,只能實現(xiàn)它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation拐邪。
- GCD
*Grand Central Dispatch是由蘋果開發(fā)的一個多核編程的解決方案慰毅。iOS4.0+才能使用。
- 優(yōu)點
- 最高效扎阶,避開并發(fā)陷阱汹胃。
- 蘋果官方推薦使用婶芭。
- 使用比上面2種更為簡單。
- 性能更好着饥,GCD自動根據(jù)系統(tǒng)負載來增減線程數(shù)量犀农,這就減少了上下文切換以及增加了計算效率。
- 開發(fā)者只需要告訴 GCD 想要如何執(zhí)行什么任務宰掉,不需要編寫任何線程管理代碼呵哨。
- 缺點
- 基于C實現(xiàn)。
三轨奄、如何選擇
- 簡單而安全的選擇NSOperation實現(xiàn)多線程即可孟害。
- 處理大量并發(fā)數(shù)據(jù),又追求性能效率的選擇GCD挪拟。
- NSThread本人選擇基本上是在做些小測試上使用挨务。
- 個人推薦使用gcd。
四玉组、生命周期
-
無論使用哪種方式創(chuàng)建的線程谎柄,在正常情況下它的生命周期都是一樣的。
狀態(tài)示意圖.png 概念
新建:實例化線程對象
- 就緒:向線程對象發(fā)送start消息球切,線程對象被加入可調度線程池等待CPU調度。
- 運行:CPU 負責調度可調度線程池中線程的執(zhí)行绒障。線程執(zhí)行完成之前吨凑,狀> * 態(tài)可能會在就緒和運行之間來回切換。就緒和運行之間的狀態(tài)變化由CPU負> * 責户辱,程序員不能干預鸵钝。
- 阻塞:當滿足某個預定條件時,可以使用休眠或鎖庐镐,阻塞線程執(zhí)行恩商。sleepForTimeInterval(休眠指定時長),sleepUntilDate(休眠到指定日期)必逆,@synchronized(self):(互斥鎖)怠堪。
- 死亡:正常死亡,線程執(zhí)行完畢名眉。非正常死亡粟矿,當滿足某個條件后,在線程> * 內部中止執(zhí)行/在主線程中止線程對象
- 還有線程的exit和cancel
- [NSThread exit]:一旦強行終止線程损拢,后續(xù)的所有代碼都不會被執(zhí)行陌粹。
- [thread cancel]取消:并不會直接取消線程,只是給線程對象添加 isCancelled 標記福压。
五掏秩、使用方法(詳細介紹GCD的使用方法)
- NSThread 創(chuàng)建線程
//動態(tài)創(chuàng)建線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:@"one"];
thread.threadPriority = 1;
[thread start];
//靜態(tài)創(chuàng)建線程
[NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:@"two"];
//隱式創(chuàng)建線程
[self performSelectorInBackground:@selector(threadAction:) withObject:@"three"];
//響應方法
-(void)threadAction:(id)object
{
NSLog(@"object = %@",object);
}
- 線程通訊
//在指定線程上執(zhí)行操作
[self performSelector:@selector(threadAction:) onThread:thread withObject:nil waitUntilDone:YES];
//在主線程上執(zhí)行操作
[self performSelectorOnMainThread:@selector(threadAction:) withObject:nil waitUntilDone:YES];
//在當前線程執(zhí)行操作
[self performSelector:@selector(threadAction:) withObject:nil];
- NSOperation
//NSInvocationOperation創(chuàng)建線程或舞。
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(threadAction:) object:@"six"];
//[invocationOperation start];//直接會在當前線程主線程執(zhí)行
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:invocationOperation];
GCD
1.任務和隊列
- 1.1 任務
- 就是執(zhí)行操作的意思,換句話說就是你在線程中執(zhí)行的那段代碼蒙幻。在 GCD 中是放在 block 中的映凳。
- 執(zhí)行任務有兩種方式:同步執(zhí)行(sync)和異步執(zhí)行(async)。兩者的主要區(qū)別是:是否等待隊列的任務執(zhí)行結束杆煞,以及是否具備開啟新線程的能力魏宽。
同步執(zhí)行(sync):
* 同步添加任務到指定的隊列中,在添加的任務執(zhí)行結束之前决乎,會一直等待,直到隊列里面的任務完成之后再繼續(xù)執(zhí)行队询。
* 只能在當前線程中執(zhí)行任務,不具備開啟新線程的能力构诚。
異步執(zhí)行(async):
* 異步添加任務到指定的隊列中蚌斩,它不會做任何等待,可以繼續(xù)執(zhí)行任務范嘱。
* 可以在新的線程中執(zhí)行任務送膳,具備開啟新線程的能力。
1.2 隊列
- 這里的隊列指執(zhí)行任務的等待隊列丑蛤,即用來存放任務的隊列叠聋。隊列是一種特殊的線性表,采用 FIFO(先進先出)的原則受裹,即新任務總是被插入到隊列的末尾碌补,而讀取任務的時候總是從隊列的頭部開始讀取。每讀取一個任務棉饶,則從隊列中釋放一個任務厦章。
- 在 GCD 中有兩種隊列:串行隊列和并發(fā)隊列。兩者都符合 FIFO(先進先出)的原則照藻。兩者的主要區(qū)別是:執(zhí)行順序不同袜啃,以及開啟線程數(shù)不同。
串行隊列(Serial Dispatch Queue):
* 每次只有一個任務被執(zhí)行幸缕。讓任務一個接著一個地執(zhí)行群发。(只開啟一個線程,一個任務執(zhí)行完畢后发乔,再執(zhí)行下一個任務)
* 對于串行隊列也物,GCD 提供了的一種特殊的串行隊列:主隊列(Main Dispatch Queue),所有放在主隊列中的任務,都會放到主線程中執(zhí)行列疗。
并發(fā)隊列(Concurrent Dispatch Queue):
* 可以讓多個任務并發(fā)(同時)執(zhí)行滑蚯。(可以開啟多個線程,并且同時執(zhí)行任務)
注意:并發(fā)隊列的并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
* 對于并發(fā)隊列,GCD 默認提供了全局并發(fā)隊列(Global Dispatch Queue)告材。
2. GCD使用步驟
- 創(chuàng)建一個隊列(串行隊列或并發(fā)隊列)
- 將任務追加到任務的等待隊列中坤次,然后系統(tǒng)就會根據(jù)任務類型執(zhí)行任務(同步執(zhí)行或異步執(zhí)行)
3. 隊列的創(chuàng)建
- 可以使用dispatch_queue_create來創(chuàng)建隊列,需要傳入兩個參數(shù)斥赋,第一個參數(shù)表示隊列的唯一標識符缰猴,用于 DEBUG,可為空疤剑,Dispatch Queue 的名稱推薦使用應用程序 ID 這種逆序全程域名滑绒;第二個參數(shù)用來識別是串行隊列還是并發(fā)隊列。DISPATCH_QUEUE_SERIAL 表示串行隊列隘膘,DISPATCH_QUEUE_CONCURRENT 表示并發(fā)隊列疑故。
// 串行隊列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
// 并發(fā)隊列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
4. 任務的創(chuàng)建
- GCD 提供了同步執(zhí)行任務的創(chuàng)建方法dispatch_sync和異步執(zhí)行任務創(chuàng)建方法dispatch_async。
// 同步執(zhí)行任務創(chuàng)建方法
dispatch_sync(queue, ^{
// 這里放同步執(zhí)行任務代碼
});
// 異步執(zhí)行任務創(chuàng)建方法
dispatch_async(queue, ^{
// 這里放異步執(zhí)行任務代碼
});
5. 基本使用
組合方式對比.png
-
同步執(zhí)行 + 并發(fā)隊列
同步執(zhí)行 + 并發(fā)隊列.png
從上圖可以看出:
- 所有任務都是在當前線程(主線程)中執(zhí)行的弯菊,沒有開啟新的線程(同步執(zhí)行不具備開啟新線程的能力)纵势。
- 所有任務都在打印的syncConcurrent---begin和syncConcurrent---end之間執(zhí)行的(同步任務需要等待隊列的任務執(zhí)行結束)。
- 任務按順序執(zhí)行的管钳。按順序執(zhí)行的原因:雖然并發(fā)隊列可以開啟多個線程钦铁,并且同時執(zhí)行多個任務。但是因為本身不能創(chuàng)建新線程才漆,只有當前線程這一個線程(同步任務不具備開啟新線程的能力)牛曹,所以也就不存在并發(fā)。而且當前線程只有等待當前隊列中正在執(zhí)行的任務執(zhí)行完畢之后醇滥,才能繼續(xù)接著執(zhí)行下面的操作(同步任務需要等待隊列的任務執(zhí)行結束)黎比。所以任務只能一個接一個按順序執(zhí)行,不能同時被執(zhí)行腺办。
- 特點:在當前線程中執(zhí)行任務焰手,不會開啟新線程糟描,執(zhí)行完一個任務怀喉,再執(zhí)行下一個任務。
-
異步執(zhí)行 + 并發(fā)隊列
異步執(zhí)行 + 并發(fā)隊列.png
從上圖可以看出:
- 除了當前線程(主線程)船响,系統(tǒng)又開啟了3個線程躬拢,并且任務是交替/同時執(zhí)行的。(異步執(zhí)行具備開啟新線程的能力见间。且并發(fā)隊列可開啟多個線程聊闯,同時執(zhí)行多個任務)。
- 所有任務是在打印的syncConcurrent---begin和syncConcurrent---end之后才執(zhí)行的米诉。說明當前線程沒有等待菱蔬,而是直接開啟了新線程,在新線程中執(zhí)行任務(異步執(zhí)行不做等待,可以繼續(xù)執(zhí)行任務)拴泌。
- 特點:可以開啟多個線程魏身,任務交替(同時)執(zhí)行。
-
同步執(zhí)行 + 串行隊列
同步執(zhí)行 + 串行隊列.png
從上圖可以看出:
- 所有任務都是在當前線程(主線程)中執(zhí)行的蚪腐,并沒有開啟新的線程(同步執(zhí)行不具備開啟新線程的能力)箭昵。
- 所有任務都在打印的syncConcurrent---begin和syncConcurrent---end之間執(zhí)行(同步任務需要等待隊列的任務執(zhí)行結束)。
- 任務是按順序執(zhí)行的(串行隊列每次只有一個任務被執(zhí)行回季,任務一個接一個按順序執(zhí)行)家制。
- 特點:不會開啟新線程,在當前線程執(zhí)行任務泡一。任務是串行的颤殴,執(zhí)行完一個任務,再執(zhí)行下一個任務瘾杭。
-
異步執(zhí)行 + 串行隊列
異步執(zhí)行 + 串行隊列.png
從上圖可以看出:
- 開啟了一條新線程(異步執(zhí)行具備開啟新線程的能力诅病,串行隊列只開啟一個線程)。
- 所有任務是在打印的syncConcurrent---begin和syncConcurrent---end之后才開始執(zhí)行的(異步執(zhí)行不會做任何等待粥烁,可以繼續(xù)執(zhí)行任務)贤笆。
- 任務是按順序執(zhí)行的(串行隊列每次只有一個任務被執(zhí)行,任務一個接一個按順序執(zhí)行)讨阻。
- 特點:會開啟一條新線程芥永,但是因為任務是串行的,執(zhí)行完一個任務钝吮,再執(zhí)行下一個任務埋涧。
結尾
- 以上純屬個人觀點,如有不對歡迎指出奇瘦。