GCD是通過C語言編寫的,為多核并行運算提出了解決方案。在GCD中,GCD會自動利用多核處理器并且自動管理線程的生命周期(線程的創(chuàng)建、調(diào)度、銷毀)。
-
GCD用有任務和隊列兩個基本概念
- 任務:就是你想在線程中要做的事情。
- 隊列:GCD會將遵循FIFO(操作系統(tǒng)中的概念)的原則,將隊列中的任務取出放到對應線程中去執(zhí)行。
-
GCD簡單的使用格式
//同步方式執(zhí)行任務 dispatch_sync(dispatch_queue_t queue, ^(void)block); //異步方式執(zhí)行任務 dispatch_async(dispatch_queue_t queue,^(void)block);
- queue:任務添加到的隊列 ,block:執(zhí)行任務的代碼。
- 同步不能開啟一個新線程,只能在當前線程中執(zhí)行任務。
- 異步能開啟一個新的線程,并在新線程中執(zhí)行任務。(異步函數(shù)用在主隊列上不會開新的線程)
- queue的類型
- 并發(fā)隊列:多個任務并發(fā)執(zhí)行。并發(fā)功能只在dispatch_async中有效。
- 串行隊列:任務一個接著一個的執(zhí)行。
-
隊列的獲得:
1.創(chuàng)建一個隊列:
//創(chuàng)建隊列queue dispatch_queue_t queue = dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
//釋放隊列(非ARC)
dispatch_release(queue);
* label:隊列的名稱,一般用功能命名。
* attr:隊列的類型:
* DISPATCH_QUEUE_SERIAL 串行隊列。
* DISPATCH_QUEUE_CONCURRENT 并發(fā)隊列。
2.使用GCD提供的全局并發(fā)隊列,整個應用都可以使用。(并發(fā)隊列)
```
dispatch_queue_t queue = dispatch_get_global_queue(long identifier, unsigned long flags);
```
* identifier: 優(yōu)先級。(由高到低)
* DISPATCH_QUEUE_PRIORITY_HIGH 2
* DISPATCH_QUEUE_PRIORITY_DEFAULT 0 (一般使用這個)
* DISPATCH_QUEUE_PRIORITY_LOW (-2)
* DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
* flags:官方文檔上寫的是 ```Flags that are reserved for future use. Always specify 0 for this parameter.``` 所以我們寫0就好了。
3.主隊列(串行隊列)
* 主隊列的任務會放到主線程中去執(zhí)行。
```
dispatch_queue_t queue = dispatch_get_main_queue();
//獲得主隊列
```
4.總結:
* 并發(fā)隊列獲得的兩種方式
* dispatch_queue_create,隊列參數(shù):DISPATCH_QUEUE_CONCURRENT
* dispatch_get_global_queue
* 串行隊列獲得的兩種方式
* dispatch_queue_create, 隊列參數(shù):DISPATCH_QUEUE_SERIAL
* dispatch_get_main_queue
5.同步函數(shù)和異步函數(shù)的區(qū)別
```
-(void)sync
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^{
NSLog(@"1-%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-%@",[NSThread currentThread]);
});
NSLog(@"END");
}
-(void)async
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"1-%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"1-%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"1-%@",[NSThread currentThread]);
});
NSLog(@"END");
}
```
```由此可知同步函數(shù)(sync)要執(zhí)行完線程,才能執(zhí)行完當前任務。異步函數(shù)(async)執(zhí)行完當前任務,再執(zhí)行任務里的線程。```
6.不同的隊列和同步函數(shù)/異步函數(shù)所產(chǎn)生的效果
隊列的類型 | 并發(fā)隊列 | 手動創(chuàng)建的串行隊列 | 主隊列
-----|------|---- |----
同步(sync) | 不開啟新線程,串行執(zhí)行任務 | 不開啟新線程,串行執(zhí)行任務 | 不開啟新線程,串行執(zhí)行任務
異步(async) | 開啟新線程,并發(fā)執(zhí)行任務| 開啟新線程,串行執(zhí)行任務 |不開啟新線程,串行執(zhí)行任務
- 使用sync(同步函數(shù))往當前串行隊列添加任務,會使當前串行隊列侵入死循環(huán)。
* 從子線程回到主線程
```
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//子線程中執(zhí)行的操作
dispatch_async(dispatch_get_main_queue(), ^{
//回到主線程的操作
});
});
```
* dispatch_barrier的使用
```
dispatch_barrier_async( dispatch_queue_t queue, dispatch_block_t block);
//在前面的任務執(zhí)行結束后它才執(zhí)行,它后面的任務要等到它執(zhí)行完才會執(zhí)行。Apple官方文檔里這樣描 述:The queue you specify should be a concurrent queue that you create yourself using the dispatch_queue_create function.所以我們要使用自己創(chuàng)建的隊列,而不能使用 dispatch_get_global_queue。
```
* 延時函數(shù)
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
//delay為延時時間,延時1s就寫1.0
//通過runloop實現(xiàn)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
code to be executed after a specified delay
});
// delayInSeconds為延時時間,延時1s就寫1.0
//dispatch_get_main_queue() 代表在主隊列中執(zhí)行任務,如果想在子線程中執(zhí)行任務,把此隊列改為并發(fā)隊列和串行隊列就行。
[NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval) target:(nonnull id) selector:(nonnull SEL) userInfo:(nullable id) repeats:(BOOL)]
//NSTimeInterval為延時時間,延時1s就寫1.0
//nonnull id 為self
//nullable id 為nil
//repeats:代表是否重復,不重復填NO
//通過runloop實現(xiàn)
* 一次性代碼
* dispatch_once函數(shù)能使某段代碼,在程序運行過程中只執(zhí)行一次,不同于懶加載(懶加載每次生成新對象都要使用),它可以用于加載程序里只能加載一次的資源。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
code to be executed once
});
//onceToken是一個標記,標記代碼有沒有執(zhí)行過,不要修改
* 快速迭代(遍歷)
dispatch_apply(size_t iterations, dispatch_queue_t queue, ^(size_t index) {
code
});
//iterations 迭代次數(shù)。迭代2次就寫2。
//queue 隊列。
//index 索引。
* 隊列組
* 如過一個需求是先完成一個或者多個異步操作,完成了它們之后才能執(zhí)行下一個異步操作,此時我們就需要隊列組。
1.創(chuàng)建一個組
```
dispatch_group_t group = dispatch_group_create();
```
2.添加到組
```
dispatch_group_async(dispatch_group_t _Nonnull group, dispatch_queue_t _Nonnull queue, ^(void)block)
* group是你創(chuàng)建的組,queue為你創(chuàng)建的隊列,block為執(zhí)行任務的代碼。
* 多個任務就要多次調(diào)用此函數(shù)
3.組里的任務都執(zhí)行完之后dispatch_group_notify函數(shù)
```
dispatch_group_notify(dispatch_group_t _Nonnull group, dispatch_queue_t _Nonnull queue, ^(void)block)
* group為執(zhí)行完任務的組,queue在哪個任務執(zhí)行的隊列,block為執(zhí)行任務的代碼。
* 如果之前的任務在queue隊列中執(zhí)行,我最后想回到主線程,那么在queue的參數(shù)為dispatch_get_main_queue()即可。