目錄
- 知識點概況
- 隊列和任務(wù)
- 并發(fā)和并行
- 常用場景
知識點
什么是GCD?以下摘自蘋果的官方說明
Grand Central Dispatch (GCD)是異步執(zhí)行任務(wù)的技術(shù)之一,一般將應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)級實現(xiàn)。開發(fā)者只需要定義想執(zhí)行的任務(wù)并追加到適當?shù)腄ispatch Queue中,GCD就能生成必要的線程并計劃執(zhí)行任務(wù)。由于線程管理是作為系統(tǒng)的一部分實現(xiàn)的,因此可統(tǒng)一管理,也可執(zhí)行任務(wù),這樣就比以前的線程更有效率。
GCD中有2個核心概念:
1. 任務(wù)和隊列
-
任務(wù):執(zhí)行什么操作,任務(wù)有兩種執(zhí)行方式: 同步函數(shù) 和 異步函數(shù),他們之間的區(qū)別是
- 同步:只能在當前線程中執(zhí)行任務(wù),不具備開啟新線程的能力,任務(wù)立刻馬上執(zhí)行,會阻塞當前線程并等待 Block中的任務(wù)執(zhí)行完畢,然后當前線程才會繼續(xù)往下運行
- 異步:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力,但不一定會開新線程,當前線程會直接往下執(zhí)行,不會阻塞當前線程
-
隊列:用來存放任務(wù),分為串行隊列 和 并行隊列
- 串行隊列(Serial Dispatch Queue)
讓任務(wù)一個接著一個地執(zhí)行(一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù)) - 并行隊列(Concurrent Dispatch Queue)
可以讓多個任務(wù)并行(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù))
- 串行隊列(Serial Dispatch Queue)
2. 并發(fā)和并行的區(qū)別
(并發(fā)和并行的區(qū)別:并發(fā)是同一時間內(nèi)執(zhí)行多個任務(wù),并行是同一時刻執(zhí)行多個任務(wù)!)
* 并發(fā):一個處理器同時處理多個任務(wù)。
* 并行:多個處理器或者是多核的處理器同時處理多個不同的任務(wù).
前者是邏輯上的同時發(fā)生(simultaneous),而后者是物理上的同時發(fā)生.

3. GCD API 常用場景
應(yīng)用場景1:等待現(xiàn)在執(zhí)行中處理結(jié)束,多任務(wù)則按順序進行-> serialQueue() <對應(yīng)Demo中函數(shù)>
應(yīng)用場景2:不等待現(xiàn)在執(zhí)行中處理結(jié)束,多任務(wù)并行進行。適用于耗時操作,沒有前后邏輯順序或依賴,返回順序取決于本身執(zhí)行完耗時 -> concurrentQueue()
應(yīng)用場景3:不論任何函數(shù)生成的隊列,如果想指定 A隊列 與 B隊列 擁有相同優(yōu)先級 -> dispatch_set_target_queue()
(知識點:優(yōu)先級 -> 并不是線程按等級順序來執(zhí)行完結(jié)束,而是系統(tǒng)處理器優(yōu)先分配處理,并不代表該線程最先處理完(只是會哭的孩子有奶吃!)應(yīng)用場景4:在追加多個處理全部結(jié)束后想執(zhí)行結(jié)束處理 -> dispatch_group()
應(yīng)用場景5:訪問數(shù)據(jù)庫或文件時,為避免數(shù)據(jù)競爭 -> dispatch_barrier_async()
應(yīng)用場景6:將Block指定次數(shù)的添加到Dispatch queue中 -> dispatch_apply()
應(yīng)用場景7:在大量處理追加到queue中,對已添加過未執(zhí)行的處理進行管理(掛起/喚醒) -> dispatch_suspend__dispatch_resume()
應(yīng)用場景8:在并行處理更新數(shù)據(jù),會產(chǎn)生數(shù)據(jù)不一的情況,雖然串行和柵欄函數(shù)(dispatch_barrier_async)也可以解決,但更細量化處理到任務(wù)中一個方法調(diào)用 -> dispatchSemaphore()
Demo
(可直接復(fù)制到Xcode中查看)
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self gcdApi];
}
-(void)gcdApi{
[self dispatch_queue];
[self dispatch_set_target_queue];
[self dispatch_group];
[self dispatch_barrier_async];
[self dispatch_apply];
[self dispatch_suspend__dispatch_resume];
[self dispatchSemaphore];
}
/** 隊列
- 1.串行(Serial dispatch、Main dispatch)
- 2.并行(Concurrent dispatch)
*/
#pragma mark - Queue
-(void)dispatch_queue{
[self serialQueue];
[self concurrentQueue];
}
-(void)serialQueue{
/**
dispatch_queue_create 生成串行隊列
- Parameters:
- value1: 自定義
- value2: NULL: 默認先進先出(FIFO) 即串行
*/
dispatch_queue_t mySerial = dispatch_queue_create("com.example.gcd.MySerialQueue", NULL);
/***
* 異步線程加入串行隊列 -> 會開辟新線程 但執(zhí)行順序onebyone,有串行隊列性質(zhì)決定
*/
dispatch_async(mySerial, ^{
NSLog(@"serialQueue_task1");
});
dispatch_async(mySerial, ^{
NSLog(@"serialQueue_task2");
});
// dispatch_release(mySerial);
}
-(void)concurrentQueue{
/**
全局隊列,并行
@ Parameters:
* value1: 優(yōu)先級 (注意:由于通過XNU內(nèi)核用于GCD并不能保證時效性,因此執(zhí)行高優(yōu)先級只是大致判斷并不精準,在處理的執(zhí)行可有可無下按優(yōu)先級)
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
* value2: 待留參數(shù),傳遞除0以外的任何值都可能導(dǎo)致一個空返回值
*/
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/***
* 異步線程加入全局隊列 -> 并行
*/
dispatch_async(global, ^{
NSLog(@"concurrentQueue_task1");
});
dispatch_async(global, ^{
NSLog(@"concurrentQueue_task2");
});
}
#pragma mark - dispatch_set_target_queue
-(void)dispatch_set_target_queue{
dispatch_queue_t createSerial = dispatch_queue_create("com.exmple.gcd.targetSerialQueue", NULL);
dispatch_queue_t globelBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
/***
* createSerial 擁有 globelBackground 相同的優(yōu)先級
*/
dispatch_set_target_queue(createSerial, globelBackground);
}
#pragma mark - dispatch_Group
-(void)dispatch_group{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"blk0");
});
dispatch_group_async(group, queue, ^{
NSLog(@"blk1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"blk2");
});
/**
* 追加三個Block到globel_queue中,等Block中全部執(zhí)行完畢,就會執(zhí)行 dispatch_get_main_queue中的Block
*/
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Done!");
});
//也可以使用wait, DISPATCH_TIME_FOREVER表示一直等待,也可以是一段時間內(nèi)
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// NSLog(@"Done!");
//blk0
//blk1
//blk2
//Done!
}
#pragma mark - dispatch_barrier_async
-(void)dispatch_barrier_async{
//用dispatch_queue_create函數(shù)生成一個Concurrent Dispatch Queue
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
NSLog(@"blk0_reading");
});
dispatch_async(concurrentQueue, ^{
NSLog(@"blk1_reading");
});
/**
* 在blk1結(jié)束后,blk2開始前寫入,將Block追加到queue中,可以是異步/同步,同步須考慮避免死鎖
*/
dispatch_barrier_async(concurrentQueue, ^{
NSLog(@"blk_writing");
});
dispatch_async(concurrentQueue, ^{
NSLog(@"blk2_reading");
});
dispatch_async(concurrentQueue, ^{
NSLog(@"blk3_reading");
});
}
#pragma mark - dispatch_apply
-(void)dispatch_apply{
/**
* 將Block指定次數(shù)的添加到Dispatch queue中,并開辟多個線程
*/
dispatch_queue_t globel = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, globel, ^(size_t index) {
NSLog(@"%zu",index);
});
NSLog(@"done");
//2
//3
//6
//...
//9
//done
}
#pragma mark - dispatch_suspend__dispatch_resume
-(void)dispatch_suspend__dispatch_resume{
/**
* 在大量處理追加到queue中,對已添加過未執(zhí)行的處理暫停 進行管理開關(guān)(掛起/喚醒)
*/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_suspend(queue);
//dispatch_resume恢復(fù)指定的queue
dispatch_resume(queue);
}
#pragma mark - dispatchSemaphore
-(void)dispatchSemaphore{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);//創(chuàng)建信號量初始值為1
NSMutableArray *arry = [[NSMutableArray alloc]init];
for (int i = 0; i<1000; i++) {
dispatch_async(queue, ^{
//等待semaphore,計數(shù)為0時等待
//一直等待,直到Dispatch_semaphore的計數(shù)值>=1減一并執(zhí)行
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//-1,
/**
* 由于semphore經(jīng)wait減一,此時計數(shù)值為0,可向下進行
*/
//訪問arry類對象的線程,只有一個,可以安全訪問
[arry addObject:@1];
//onebyone
dispatch_semaphore_signal(semaphore);//+1
});
}
}
Github地址 : https://github.com/one-tea/GCD-API
參考資料:
grand-central-dispatch-in-depth-part:
https://github.com/nixzhu/dev-blog/blob/master/2014-04-19-grand-central-dispatch-in-depth-part-1.md
http://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2
iOS - 多線程你看全不全:https://juejin.im/entry/57dcc1cc0bd1d00057e97dc7
IOS多線程之GCD的執(zhí)行原理:http://www.itdecent.cn/p/5840523fb3ea