多執行緒:基礎內容
阿新 • • 發佈:2018-11-07
一、iOS中的常見多執行緒方案
- iOS 中 常見的多執行緒 方案
- pthread 和 NSThread 是 程式設計師自己建立 執行緒,自己管理什麼時候開啟,什麼時候結束。
- GCD 和 NSOperation 則不用程式設計師自己管理,是系統管理。
- NSThread 、 GCD 和 NSOperation 的底層使用的是 pthread。 他們都是包裝的 pthread。
- 面試題:iOS的多執行緒方案有哪幾種?你更傾向於哪一種?
- iOS的多執行緒方案有哪幾種:pthread、NSThread、GCD 和 NSOperation
- 你更傾向於哪一種: GCD 或 NSOperation
二、GCD 常用函式
在子個執行緒想要做某些事情,可以通過GCD 的 這幾個函式。
- GCD中有2個用來執行任務的函式
-
用同步的方式執行任務
- dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
- queue:佇列
- block:任務
-
用非同步的方式執行任務
- dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
- 舉例:非同步方式執行任務
// 全域性併發佇列:姑且理解為系統為我們開啟的一些全域性執行緒 /** dispatch_queue_t q = dispatch_get_global_queue(long identifier, unsigned long flags) 引數型別為: long identifier:ios 8.0 告訴佇列執行任務的“服務質量 quality of service”,系統提供的引數有: QOS_CLASS_USER_INTERACTIVE 0x21, 使用者互動(希望儘快完成,使用者對結果很期望,不要放太耗時操作) QOS_CLASS_USER_INITIATED 0x19, 使用者期望(不要放太耗時操作) QOS_CLASS_DEFAULT 0x15, 預設(不是給程式設計師使用的,用來重置對列使用的) QOS_CLASS_UTILITY 0x11, 實用工具(耗時操作,可以使用這個選項) QOS_CLASS_BACKGROUND 0x09, 後臺 QOS_CLASS_UNSPECIFIED 0x00, 未指定 iOS 7.0 之前 優先順序 DISPATCH_QUEUE_PRIORITY_HIGH 2 高優先順序 DISPATCH_QUEUE_PRIORITY_DEFAULT 0 預設優先順序 DISPATCH_QUEUE_PRIORITY_LOW (-2) 低優先順序 DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 後臺優先順序 BACKGROUND表示使用者不需要知道任務什麼時候完成,如果選擇這個選項速度慢得令人髮指,非常不利於除錯!對於優先順序推薦不要搞得太負責,就用最簡單,以免發生優先順序反轉。 unsigned long flags:蘋果官方文件是這樣解釋的: Flags that are reserved for future use。標記是為了未來使用保留的!所以這個引數應該永遠指定為0 如果做ios8.0與ios7.0的適配,可以這樣建立全域性佇列: dispatch_queue_t q = dispatch_get_global_queue(0, 0); 試著用全域性佇列來做一下非同步操作,看看是否為併發執行,如下程式碼 dispatch_queue_t q = dispatch_get_global_queue(0, 0); */ dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 非同步方式執行任務 // 列印結果是 3 ,也就是在 3號子執行緒執行的任務 dispatch_async(queue, ^{ NSLog(@"執行任務 -%@",[NSThread currentThread]); }); // 如果是同步方式執行任務 // 列印結果是 1 // 同步方式:在當前執行緒執行任務 dispatch_sync(queue, ^{ NSLog(@"執行任務 -%@",[NSThread currentThread]); });
三、GCD的佇列
- GCD的佇列可以分為2大型別
-
併發佇列(Concurrent Dispatch Queue)
- 可以讓多個任務併發(同時)執行(自動開啟多個執行緒同時執行任務)
- 併發功能只有在非同步(dispatch_async)函式下才有效
-
序列佇列(Serial Dispatch Queue)
- 讓任務一個接著一個地執行(一個任務執行完畢後,再執行下一個任務)
- 舉例: 併發佇列 + 非同步任務
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 非同步任務
dispatch_async(queue, ^{
for (int i = 0 ; i < 5; i++) {
NSLog(@"執行任務1 - %@", [NSThread currentThread]);
}
});
// 非同步任務
dispatch_async(queue, ^{
for (int i = 0 ; i < 5; i++) {
NSLog(@"執行任務2 - %@", [NSThread currentThread]);
}
});
執行結果:
- 序列佇列 + 非同步任務
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 非同步任務
dispatch_async(queue, ^{
for (int i = 0 ; i < 5; i++) {
NSLog(@"執行任務1 - %@", [NSThread currentThread]);
}
});
// 非同步任務
dispatch_async(queue, ^{
for (int i = 0 ; i < 5; i++) {
NSLog(@"執行任務2 - %@", [NSThread currentThread]);
}
});
結果:
- 序列佇列 + 同步任務: 只在主執行緒執行
// 序列佇列
dispatch_queue_t queue = dispatch_queue_create("WYGCD", DISPATCH_QUEUE_SERIAL);
// 同步任務
dispatch_sync(queue, ^{
for (int i = 0 ; i < 3; i++) {
NSLog(@"執行任務1 - %@", [NSThread currentThread]);
}
});
// 同步任務
dispatch_sync(queue, ^{
for (int i = 0 ; i < 3; i++) {
NSLog(@"執行任務2 - %@", [NSThread currentThread]);
}
});
結果:
- 不管是序列佇列還是併發佇列,只要跟 同步任務在一起,就是在當前執行緒按照順序執行。
四、容易混淆的術語
- 有4個術語比較容易混淆:同步、非同步、併發、序列
- 同步和非同步主要影響:能不能開啟新的執行緒
- 同步:在當前執行緒中執行任務,不具備開啟新執行緒的能力
- 非同步:在新的執行緒中執行任務,具備開啟新執行緒的能力
- 併發和序列主要影響:任務的執行方式
- 併發:多個任務併發(同時)執行
- 序列:一個任務執行完畢後,再執行下一個任務
- dispatch_sync 和 dispatch_async 用來控制是否要開啟新的執行緒
- 佇列的型別,決定了任務的執行方式(併發、序列)
- 是一個接著一個執行
- 還是 任務一起執行
- dispatch_async 只是具備了 開啟新執行緒的能力,不代表一定會開啟新執行緒。下面的程式碼就不具備開啟新執行緒,列印結果是 1 (主執行緒)。
- 這是因為 queue 是 主佇列
- 也就是說 ,任務是放在了 主佇列,到時候就是在主執行緒中執行
五、各種佇列的執行效果
- 主佇列 是一種特殊的序列佇列