簡答的復習了一下GCD的一些簡單操作,這里做一個筆記,方便以后查看。
- Dispatch Queue
- 自定義串、并行隊列
- 程序進程缺省隊列
- 主線程隊列
- 同步/異步、串行/并行使用
- 死鎖問題
- dispatch_after
- dispatch_group
Dispatch Queue
Serial Dispatch Queue
按添加進隊列的順序(先進先出)一個接一個的執行Concurrent Dispatch Queue
并發執行隊列里的任務
1.1 自定義串、并行隊列
并行隊列:DISPATCH_QUEUE_CONCURRENT
串行隊列:DISPATCH_QUEUE_SERIAL
//創建一個名稱為‘com.company.xxx’的串行隊列
dispatch_queue_t serialQueue = dispatch_queue_create("com.company.xxx", DISPATCH_QUEUE_SERIAL);
//創建一個名稱為‘com.xxx’的并行隊列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.company.xxx", DISPATCH_QUEUE_CONCURRENT);
Note:
1)參數一是隊列的名稱,一般是使用倒序的全域名。雖然可以不給隊列指定一個名稱,但是有名稱的隊列可以讓我們在遇到問題時更好調試
2)當參數二為nil時返回Serial Dispatch Queue(串行隊列)
,如上面那個例子,當指定為DISPATCH_QUEUE_CONCURRENT
時返回Concurrent Dispatch Queue(并行隊列)
1.2 程序進程缺省隊列
高優先級隊列:DISPATCH_QUEUE_PRIORITY_HIGH
中優先級隊列:DISPATCH_QUEUE_PRIORITY_DEFAULT
低優先級隊列:DISPATCH_QUEUE_PRIORITY_LOW
//獲取程序缺省并行隊列,第二個參數固定為0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
Note:
1)需要注意的是,三個隊列不代表三個線程,可能會有更多的線程。并發隊列可以根據實際情況來自動產生合理的線程數,也可理解為dispatch隊列實現了一個線程池的管理,對于程序邏輯是透明的。
2)獲取Global Dispatch Queue
的時候可以指定優先級,可以根據自己的實際情況來決定使用哪種優先級
1.3 主線程隊列
//獲取主線程串行隊列
dispatch_queue_t queue = dispatch_get_main_queue();
三者對比
隊列 | 串行 | 并行 |
---|---|---|
自定義隊列 | √ | √ |
程序缺省隊列 | × | √ |
主線程隊列 | √ | × |
Note:
一般只在需要更新UI時我們才獲取Main Dispatch Queue
,其他情況下用Global Dispatch Queue
就滿足需求了
同步/異步、串行/并行使用
//異步執行block,函數立即返回
dispatch_async(queue, ^{
//block具體代碼
});
//同步執行block,函數不返回
dispatch_sync(queue, ^{
//block具體代碼
});
舉例:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//子線程中開始網絡請求數據
···
//更新數據模型
dispatch_sync(dispatch_get_main_queue(), ^{
//在主線程中更新UI代碼
self.view.backgroundColor = [UIColor orangeColor];
});
});
Note:
盡可能避免使用dispatch_sync
,嵌套使用時還容易引起程序死鎖
死鎖問題
- 同步串行會出現死鎖,同步并行不會造成死鎖
- 異步不管是串行還是并行都不會出現死鎖
- 異步嵌套同步或者同步嵌套異步就需要注意代碼執行順序
Note:
死鎖原因:提交到主線程隊列的時候,慎用同步dispatch_sync
方法,有可能造成死鎖。因為主線程隊列是串行隊列,要等隊列里的任務一個一個執行。所以提交一個任務到隊列,如果用同步方法就會阻塞住主線程,而主線程又要等主線程隊列里的任務都執行完才能執行那個剛提交的,所以主線程隊列里還有其他的任務的話,但他已經被阻塞住了,沒法先完成隊列里的其他任務,即,最后一個任務也沒機會執行到,于是造成死鎖。
dispatch_after
dispatch_after
能讓我們添加進隊列的任務延時執行,比如想讓一個Block在5秒后執行:
double delayTime = 5.0;
dispCatch_time_t dTime = dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(delayTime*NSEC_PER_SEC));
dispatch_after(dTime, dispatch_get_main_queue(), ^{
//delayTime秒后執行block塊
NSLog(@"block執行");
});
dispatch_after
的真正含義是在5秒后把任務添加進隊列中,并不是表示在5秒后執行,大部分情況該函數能達到我們的預期,只有在對時間要求非常精準的情況下才可能會出現問題
【拓展】
延遲執行還有另外一種方式,那就是NSObject中的performSelector:withObject:afterDelay:
以及performSelector:withObject:afterDelay:inModes:
dispatch_group
我們現在有3個Block要執行,我們不在乎它們執行的順序,我們只希望在這3個Block執行完之后再執行某個操作。這個時候就需要使用dispatch_group
了
dispatch_group_t groupQueue = dispatch_group_create();
dispatch_group_async(groupQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"1");
});
dispatch_group_async(groupQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"2");
});
dispatch_group_async(groupQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"3");
});
dispatch_group_notify(groupQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"completion");
});
在控制臺打印的結果是:
2015-07-21 22:17:57.159 GCD[9606:1327380] 3
2015-07-21 22:17:57.159 GCD[9606:1327377] 2
2015-07-21 22:17:57.159 GCD[9606:1327379] 1
2015-07-21 22:17:57.159 GCD[9606:1327377] completion
Note:
輸出的順序與添加進隊列的順序無關,因為隊列是Concurrent Dispatch Queue
,但“completion”的輸出一定是在最后的
再一次感謝您花費時間閱讀這篇文章!
微博: @Danny_呂昌輝
博客: SuperDanny
2015 年 07月 15日