文章分享至我的個人技術部落格: https://cainluo.github.io/15019074509183.html
在前面一篇文章裡, 我們大概知道了GCD
是個什麼概念, 也知道了如何建立佇列, 建立任務, 但前面的都只是理念, 估計有很多人不喜, 要開始噴我了, 這才我們來用程式碼實踐實踐, 如果沒有看過上一篇的, 可以去玩轉iOS開發:iOS中的GCD開發(一)看看.
轉載宣告:如需要轉載該文章, 請聯絡作者, 並且註明出處, 以及不能擅自修改本文.
CGD的基本使用
這裡我們就需要建立一個工程, 然後試試水:
並行佇列+同步執行
- (void)syncQueueConcurrent {
NSLog(@"開始執行任務");
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"第一個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"第二個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"第三個任務當前執行緒為: %@", [NSThread currentThread]);
});
NSLog(@"結束執行任務");
}
複製程式碼
2017-08-05 15:03:55.567 GCD-Example[14007:7612071] 開始執行任務
2017-08-05 15:03:55.567 GCD-Example[14007:7612071] 第一個任務當前執行緒為: <NSThread: 0x608000067340>{number = 1, name = main}
2017-08-05 15:03:55.567 GCD-Example[14007:7612071] 第二個任務當前執行緒為: <NSThread: 0x608000067340>{number = 1, name = main}
2017-08-05 15:03:55.568 GCD-Example[14007:7612071] 第三個任務當前執行緒為: <NSThread: 0x608000067340>{number = 1, name = main}
2017-08-05 15:03:55.568 GCD-Example[14007:7612071] 結束執行任務
複製程式碼
- 從輸出結果, 我們可以看得出, 現在當前的執行緒都為同一條, 名為
main
, 而且執行緒數只有1
. - 在執行任務的前和執行任務後, 我都加了一個
Log
, 從執行順序上我們可以知道,並行佇列+同步執行
是一個任務一個任務的去執行的.
並行佇列+非同步執行
接下來我們看看並行佇列+非同步執行
的組合:
- (void)asyncQueueConcurrent {
NSLog(@"開始執行任務");
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"第一個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三個任務當前執行緒為: %@", [NSThread currentThread]);
});
NSLog(@"結束執行任務");
}
複製程式碼
2017-08-05 15:08:40.069 GCD-Example[14052:7619255] 開始執行任務
2017-08-05 15:08:40.070 GCD-Example[14052:7619255] 結束執行任務
2017-08-05 15:08:40.070 GCD-Example[14052:7619380] 第三個任務當前執行緒為: <NSThread: 0x60800026a640>{number = 5, name = (null)}
2017-08-05 15:08:40.070 GCD-Example[14052:7619363] 第一個任務當前執行緒為: <NSThread: 0x60800026a5c0>{number = 3, name = (null)}
2017-08-05 15:08:40.070 GCD-Example[14052:7619362] 第二個任務當前執行緒為: <NSThread: 0x60000026bb00>{number = 4, name = (null)}
複製程式碼
- 從輸出的結果, 我們可以看到, 這裡的執行緒數有好幾條, 而且執行緒的名字也不知道, 並且從時間上來看到, 幾乎都是在同一時間執行任務的.
- 所以我們可以得出一個結果,
並行佇列+非同步執行
的組合除了在主佇列
上執行, 還會另外開啟多幾條執行緒來並行執行任務.
序列佇列+同步執行
繼續下一個序列佇列+同步執行
組合:
- (void)syncQueueSerial {
NSLog(@"開始執行任務");
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"第一個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"第二個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"第三個任務當前執行緒為: %@", [NSThread currentThread]);
});
NSLog(@"結束執行任務");
}
複製程式碼
2017-08-05 15:16:21.723 GCD-Example[14119:7628753] 開始執行任務
2017-08-05 15:16:21.723 GCD-Example[14119:7628753] 第一個任務當前執行緒為: <NSThread: 0x6080000794c0>{number = 1, name = main}
2017-08-05 15:16:21.724 GCD-Example[14119:7628753] 第二個任務當前執行緒為: <NSThread: 0x6080000794c0>{number = 1, name = main}
2017-08-05 15:16:21.724 GCD-Example[14119:7628753] 第三個任務當前執行緒為: <NSThread: 0x6080000794c0>{number = 1, name = main}
2017-08-05 15:16:21.724 GCD-Example[14119:7628753] 結束執行任務
複製程式碼
- 從結果看, 這個
序列佇列+同步執行
組合是一個一個任務來執行的, 都是在主佇列中完成, 並沒有開啟新執行緒. - 由於是序列佇列, 所以我們可以在上面看到, 先執行第一個開始
Log
, 然後任務都是按個新增, 最後在執行結束Log
.
序列佇列 + 非同步執行
繼續序列佇列 + 非同步執行
:
- (void)asyncQueueSerial {
NSLog(@"開始執行任務");
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"第一個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三個任務當前執行緒為: %@", [NSThread currentThread]);
});
NSLog(@"結束執行任務");
}
複製程式碼
2017-08-05 17:32:06.723 GCD-Example[14279:7669095] 開始執行任務
2017-08-05 17:32:06.723 GCD-Example[14279:7669095] 結束執行任務
2017-08-05 17:32:06.723 GCD-Example[14279:7669192] 第一個任務當前執行緒為: <NSThread: 0x60800006ee00>{number = 3, name = (null)}
2017-08-05 17:32:06.724 GCD-Example[14279:7669192] 第二個任務當前執行緒為: <NSThread: 0x60800006ee00>{number = 3, name = (null)}
2017-08-05 17:32:06.724 GCD-Example[14279:7669192] 第三個任務當前執行緒為: <NSThread: 0x60800006ee00>{number = 3, name = (null)}
複製程式碼
- 從結果來看, 我們可以看到, 是開啟新執行緒來執行任務, 但由於是
序列佇列
, 所以這裡的任務還是一個接著一個來執行的. - 另外, 這裡還有一點, 我們可以看到先列印了開發
Log
和結束Log
, 最後才執行任務, 可以說明, 這裡的任務並不是一下子就開始執行的, 是需要將任務都新增到佇列裡, 然後才開始同步執行.
主佇列
主佇列是GCD
自帶的一種特殊的佇列, 這裡有兩點需要注意一下:
- 所有放在
主佇列
裡執行的任務都會放到主執行緒
裡執行. - 我們可以通過
dispatch_get_main_queue()
獲取主佇列.
說那麼多不如直接來段程式碼:
主佇列+同步執行
- (void)syncMainQueue {
NSLog(@"開始執行任務");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"第一個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"第二個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"第三個任務當前執行緒為: %@", [NSThread currentThread]);
});
NSLog(@"結束執行任務");
}
複製程式碼
2017-08-05 17:56:24.607 GCD-Example[14437:7689741] 開始執行任務
複製程式碼
當我們執行的時候發現異常了, 斷言在執行完開始Log
之後不動了, 為什麼咧?
其實這是因為我們在ViewDidload
方法裡執行了[self syncMainQueue];
方法, 我們都知道, 同步執行是一個一個任務去執行的.
但主線還在執行[self syncMainQueue];
的時候, 我們又往主執行緒裡塞任務, 這個時候就會出現異常現象, 我們稱之為卡執行緒
.
如果要解決的話, 我們就需要在ViewDidload
裡改善一下方案:
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[self syncMainQueue];
});
}
複製程式碼
2017-08-05 18:03:33.209 GCD-Example[14492:7698292] 開始執行任務
2017-08-05 18:03:33.214 GCD-Example[14492:7698172] 第一個任務當前執行緒為: <NSThread: 0x600000066340>{number = 1, name = main}
2017-08-05 18:03:33.215 GCD-Example[14492:7698172] 第二個任務當前執行緒為: <NSThread: 0x600000066340>{number = 1, name = main}
2017-08-05 18:03:33.216 GCD-Example[14492:7698172] 第三個任務當前執行緒為: <NSThread: 0x600000066340>{number = 1, name = main}
2017-08-05 18:03:33.216 GCD-Example[14492:7698292] 結束執行任務
複製程式碼
唔, 醬紫改造就可以順利的執行完任務了, 這裡還需要提多兩點:
- 在執行的結果裡, 雖我們在
ViewDidload
用的是並行+非同步
的組合去改善的, 但這不會影響到主佇列裡的任務執行順序, 也不會開啟新執行緒. - 主佇列是屬於序列佇列, 所以我們可以看到所執行的任務是一個接著一個.
主佇列+非同步執行
最後一個組合主佇列+非同步執行
:
- (void)asyncMainQueue {
NSLog(@"開始執行任務");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"第一個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二個任務當前執行緒為: %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三個任務當前執行緒為: %@", [NSThread currentThread]);
});
NSLog(@"結束執行任務");
}
複製程式碼
2017-08-05 18:08:16.059 GCD-Example[14537:7704614] 開始執行任務
2017-08-05 18:08:16.059 GCD-Example[14537:7704614] 結束執行任務
2017-08-05 18:08:16.064 GCD-Example[14537:7704614] 第一個任務當前執行緒為: <NSThread: 0x608000261700>{number = 1, name = main}
2017-08-05 18:08:16.064 GCD-Example[14537:7704614] 第二個任務當前執行緒為: <NSThread: 0x608000261700>{number = 1, name = main}
2017-08-05 18:08:16.065 GCD-Example[14537:7704614] 第三個任務當前執行緒為: <NSThread: 0x608000261700>{number = 1, name = main}
複製程式碼
- 從結果上我們可以看到, 雖然我們用的是
非同步執行
, 具備了開啟新執行緒的能力, 但是由於這是主佇列, 所以所有的任務都是在主執行緒中, 任務也是一個接著一個執行的. - 另外, 我們可以看到, 是先執行開始
Log
, 結束Log
, 最後再執行主佇列裡的任務, 這裡我們就可以知道, 任務並不是馬上就執行的, 而是把所有任務都新增到佇列裡之後, 再執行.
總結
學完之後, 我們就可以愉快的和GCD
玩耍了, 佇列, 任務神馬的, 再也不用擔心了.
工程地址
專案地址: https://github.com/CainRun/iOS-Project-Example/tree/master/GCD-Example