標籤:
iOS多線程編程
1. 進程,線程, 任務
進程:一個程式在運行時,系統會為其分配一個進程,用以管理他的一些資源。
線程:進程內所包含的一個或多個執行單元稱為線程,線程一般情況下不持有資源,但可以使用其所在進程的資源。
任務:進程或線程中要做的事情。
在引入線程的作業系統中,通常把進程作為分配資源的基本單位,而把線程作為獨立運行和獨立調度的基本單位。
線程比進程更小,對其調度的開銷小,能夠提高系統內多個任務的並發執行程度。
一個程式至少有一個進程,一個進程至少有一個線程.一個程式就是一個進程,而一個程式中的多個任務則被稱為線程。
線程只能歸屬於一個進程並且它只能訪問該進程所擁有的資源。當作業系統建立一個進程後,該進程會自動申請一個名為主線程或首要線程的線程。應用程式(application)是由一個或多個相互協作的進程組成的。
多線程的意義在於一個應用程式中,有多個執行部分可以同時執行。提供協調機制,一方面防止進程之間和線程之間產生衝突,另一方面允許進程之間和線程之間共用資源。
2. iOS多線程編程技術
共有三種(實際上是四種,還有Pthreads,C語言架構)
> NSThread
> NSOperation
> GCD (Grand Central Dispatch)
從上到下,封裝度從低到高,封裝度越高使用越簡單,也是官方推薦使用。
三種方式的比較:
NSThread: 相對於另外兩種是比較輕量級的。此種方式是經官方封裝後的,是完全物件導向的,所以可以直接操控線程對象,非常直觀方便。但是需要自己管理線程的生命週期,線程同步,而且線程同步對資料的加鎖會有一定的系統開銷。使用比較簡單,但不夠智能,在一些簡單的情境才使用。
NSOperation: 完全物件導向的。相關的主要類有 NSOperation(任務) 和 NSOperationQueue(任務隊列),其中NSOperationQueue 在iOS4引入GCD後,其內部用GCD實現的。此種方式下不需要關心線程管理,資料同步的操作。隱藏了許多複雜的代碼,提供了簡單的API。
GCD : 是蘋果為多核並行運算提出的解決方案,會自動合理的利用更多的CPU核心(如雙核,四核)。此種方式也能自動管理線程的生命週期(建立線程,調度任務,銷毀線程),不需要自己管理,只需要告訴其要做的操作是什麼就可以。雖然也使用c語言,但因為使用了block, 使用也很方便,靈活。在GCD中也有“任務”,“隊列”的概念。
一、NSThread ===========================================
1. 使用NSThread建立並管理線程
> 建立線程
方式一:執行個體方法
[NSThread alloc] initWithTarget: selector : object:]
參數一:線程操作訊息的接收者 self
參數二:選取器方法,線程操作的方法,此方法只能帶一個參數,而且不能有傳回值
參數三:線程操作方法所帶的參數
使用該方式建立的線程不會自動啟動,需調用線程方法:
[thread start] // 開始啟動並執行線程
方式二:類方法
[NSThread detachNewThreadSelector: toTarget: withObject: ]
參數同上同名參數;
此方法建立的線程會自動啟動執行,無需手動開啟。
> 線程方法
//取消線程
- (void)cancel;
//啟動線程
- (void)start;
//設定/擷取某個線程的狀態
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;
//設定和擷取線程名字
-(void)setName:(NSString *)n;
-(NSString *)name;
//擷取當前線程
+ (NSThread *)currentThread;
//擷取主線程
+ (NSThread *)mainThread;
//使當前線程暫停一段時間,或者暫停到某個時刻
+ (void)sleepForTimeInterval:(NSTimeInterval)time;
+ (void)sleepUntilDate:(NSDate *)date;
// 設定線程優先順序
+ (BOOL)setThreadPriority:(double)p;
> 線程間的通訊
在非主線程上絕對不能去訪問UI, 必須在主線程上更新
[self performSelectorOnMainThread:@selector(updateUI:) withObject:data waitUntilDone:YES];
線程與線程間可進行資料通訊
[self performSelector:@selector(senddata:) onThread:thread2 withObject:obj waitUntilDone:YES]
> 線程同步
多個線程訪問同一共用資源時,為保證資料資源的準確性,需對資源進行加鎖,是在一個時刻上只有一個線程訪問共用資源,其他線程則排隊等待。
NSLock 鎖
[[NSLock alloc] init]
[theLock lock];
…..要訪問的共用資源
[theLock unlock];
二、NSOperation========================================================
1. NSOperation
此類是抽象類別不能直接使用。
只能使用系統定義好的子類或者自訂繼承NSOperation。
定義好的子類:NSInvocationOperation 和 NSBlockOperation
一個 NSOperation對象 對應一個任務/線程,需要將其放入 NSOperationQueue 任務隊列/線程池,才會啟動並執行任務/線程。
2. NSInvocationOperation
任務的操作執行在方法中進行
> [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(..) object:nil]
3. NSBlockOperation
任務的操作執行在block中進行
> [NSBlockOperation blockOperationWithBlock:^{
…
}]
4. NSOperationQueue 將任務添加到任務隊列中使其啟動執行
> NSOperationQueue *que = [[NSOperationQueue alloc] init] // 自訂隊列
> que.name // 隊列名稱
> que.maxConcurrentOperationCount // 最大任務並發數,設定為1時為串列執行任務。預設是-1,表示沒有限制,會同時執行隊列中的任務。
> [que addOperation:oper1] // 將任務添加到隊列中以啟動執行
除自訂隊列外:
主隊列(該隊列中的任務在主線程執行):[NSOperationQueue mainQueue]
當前隊列:[NSOperationQueue currentQueue]
5. 任務間的依賴
[oper1 addDependency:oper2] // 任務1依賴於任務2,任務1的執行必須等任務2執行完畢後才能開始
注意此操作必須是在將任務添加到隊列前執行!!!
6. SDWebImage 圖片下載原理運用了NSOperation,NSOperationQueue
三、GCD============================================================
1. GCD:任務,隊列
隊列分串列,並行隊列。
串列隊列中的任務執行:GCD會FIFO(先進先出)的取出一個任務,執行一個後,再擷取下一個,依次類推。
並行隊列中的任務執行:GCD也是按FIFO的方式取出任務,與串列的不同是:取出任務後會放倒別的線程上,然後再取出一個放到另外的線程....。 因為取任務的過程很快,看起來所有任務都是一起執行的。注意:GCD會根據系統資源控制並行的任務數量,任務太多時,不會讓所有任務同時執行。
2. 從程式上隊列分類:
主隊列:(串列隊列)dispatch_queue_t qm = dispatch_get_main_queue();
自訂隊列:(可串列,並行)dispatch_queue_t qself = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT); // 通過第二個參數指定隊列是串列DISPATCH_QUEUE_SERIAL還是並行DISPATCH_QUEUE_CONCURRENT
全域並行隊列:dispatch_queue_t qg = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3. 隊列中添加要執行的任務(同步[阻塞當前線程],非同步任務[不阻塞當前線程])
dispatch_async(qm, ^{
// 在指定的隊列中要執行的任務...
});
4. 隊列組
多個隊列可以放到一個組中。
// 建立隊列組
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
// 在指定的隊列組中,添加隊列queue, 並在queue中新增工作...
});
dispatch_group_notify(group, queue, ^{
// 指定的組裡的所有任務完成後,發送通知給指定的隊列,並執行一個任務…,通常用於在主隊列中更新ui
});
iOS多線程編程