主佇列,全域性佇列,併發佇列關係比較
多執行緒(2) - ios關於執行緒排程的三種方式之GCD
一 概念和理解
Grand Central Dispatch(多執行緒的優化技術)GCD
是一套底層API,基於C語言開發的多執行緒機制,提供了新的模式編寫併發執行的程式。
特點:
1.允許將一個程式切分為多個單一任務,然後提交到工作佇列中併發或者序列地執行
2.為多核的並行運算提出瞭解決方案,自動合理的利用CPU核心(比如雙核,四核)
3.自動的管理執行緒的生命週期(建立執行緒、排程任務、銷燬執行緒),完全不需要我們管理,只需要告訴它任務是什麼就行
4.
2.什麼是Queue佇列?
GCD使用了佇列的概念,解決了NSThread難於管理的問題,佇列實際上就是陣列的概念,通常我們把要執行的任務放到佇列中管理
特點:
1.按順序執行,先進先出
2.可以管理多執行緒,管理併發的任務,設定主執行緒
3.GCD的佇列是任務的佇列,而不是執行緒的佇列
3.什麼是任務?
任務即操作:你想要幹什麼,說白了就是一段程式碼,在GCD中,任務就是一個block
任務的兩種執行方式:
同步執行:只要是同步任務,都會在當前的執行緒執行,不會另開執行緒
非同步執行:只要是非同步任務,都會開啟新執行緒,在開啟的執行緒中執行
4.什麼是序列佇列?
依次完成每一任務
5.什麼是並行佇列?
好像所有的任務都是在同一時間執行的
6.都有哪些佇列?
Main Queue(主佇列,序列);全域性佇列(Global Queue);自己建立的佇列(Queue)
從上面的概念以及gcd所解決的問題來看,使用GCD的時候就要開始轉變觀念了。現在我們需要考慮的只是任務,佇列,佇列間同步或非同步的關係了。而不是考慮怎麼開闢執行緒,怎麼管理執行緒,所有關於執行緒的東西,我們都不需要考慮。整個程式完全就是由佇列來自動管理了。首先,整個程式是由全域性佇列來管理,然後UI的重新整理是由mainqueue管理,我們可以將我們的任務放到我們建立的佇列中去,也可以放在主佇列中,也可以放在全域性佇列中。
舉個例子:現在我們要從網路上下載一張圖片,可以直接將任務放到主佇列中去執行,但是這樣會出項一個問題,因為主佇列是處理和UI相關的任務的,所以在建立(或者重新整理)UI的時候,介面就會卡住,直到這張圖片現在完畢。所以一般的做法是首先獲取全域性佇列,然後在全域性佇列中植入下載圖片的程式碼,在下完成後,將圖片刷回UI,也就是主佇列。至於圖片什麼時候下載完畢,怎麼開闢執行緒,我們都不需要管。需要做的就是處理程式碼邏輯就行。以下是使用GCD下載圖片的程式碼
+ (void)SL_setImageView:(UIImageView *)imageView url:(NSString *)url
{
//對應全域性佇列開啟一個非同步任務
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//下載圖片資料
NSURL *imageURL = [NSURL URLWithString:url];
NSData *data = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:data];
//重新整理ImageView (回撥主執行緒)
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = image;
});
});
}
關於容易混淆概念的區分:
1, 同步,非同步,序列,併發
同步和非同步代表會不會開闢新的執行緒。序列和併發代表任務執行的方式。
同步序列和同步併發,任務執行的方式是一樣的。沒有區別,因為沒有開闢新的執行緒,所有的任務都是在一條執行緒裡面執行。
非同步序列和非同步併發,任務執行的方式是有區別的,非同步序列會開闢一條新的執行緒,佇列中所有任務按照新增的順序一個一個執行,非同步併發會開闢多條執行緒,至於具體開闢多少條執行緒,是由系統決定的,但是所有的任務好像就是同時執行的一樣。
開闢佇列的方法:
dispatch_queue_t myQueue = dispatch_queue_create("MyQueue", NULL);
/**
引數1:標籤,用於區分佇列
引數2:佇列的型別,表示這個佇列是序列佇列還是併發佇列NUll表示序列佇列,
DISPATCH_QUEUE_CONCURRENT表示併發佇列
*/
執行佇列的方法
非同步執行
dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)
同步執行
dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)
二,主佇列
主佇列:專門負責排程主執行緒度的任務,沒有辦法開闢新的執行緒。所以,在主佇列下的任務不管是非同步任務還是同步任務都不會開闢執行緒,任務只會在主執行緒順序執行。
主佇列非同步任務:現將任務放在主佇列中,但是不是馬上執行,等到主佇列中的其它所有除我們使用程式碼新增到主佇列的任務的任務都執行完畢之後才會執行我們使用程式碼新增的任務。
主佇列同步任務:容易阻塞主執行緒,所以不要這樣寫。原因:我們自己程式碼任務需要馬上執行,但是主執行緒正在執行程式碼任務的方法體,因此程式碼任務就必須等待,而主執行緒又在等待程式碼任務的完成好去完成下面的任務,因此就形成了相互等待。整個主執行緒就被阻塞了。
三,全域性佇列
全域性佇列:本質是一個併發佇列,由系統提供,方便程式設計,可以不用建立就直接使用。
獲取全域性佇列的方法:dispatch_get_global_queue(long indentifier.unsigned long flags)
/**
引數說明:
引數1:代表該任務的優先順序,預設寫0就行,不要使用系統提供的列舉型別,因為ios7和ios8的列舉數值不一樣,使用數字可以通用。
引數2:蘋果保留關鍵字,一般也寫0
*/
全域性佇列和併發佇列的區別:
1,全域性佇列沒有名字,但是併發佇列有名字。有名字可以便於檢視系統日誌
2,全域性佇列是所有應用程式共享的。
3,在mrc的時候,全域性佇列不用手動釋放,但是併發佇列需要。