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

3. GCD API 常用場(chǎng)景
應(yīng)用場(chǎng)景1:等待現(xiàn)在執(zhí)行中處理結(jié)束,多任務(wù)則按順序進(jìn)行-> serialQueue() <對(duì)應(yīng)Demo中函數(shù)>
應(yīng)用場(chǎng)景2:不等待現(xiàn)在執(zhí)行中處理結(jié)束,多任務(wù)并行進(jìn)行。適用于耗時(shí)操作,沒(méi)有前后邏輯順序或依賴,返回順序取決于本身執(zhí)行完耗時(shí) -> concurrentQueue()
應(yīng)用場(chǎng)景3:不論任何函數(shù)生成的隊(duì)列,如果想指定 A隊(duì)列 與 B隊(duì)列 擁有相同優(yōu)先級(jí) -> dispatch_set_target_queue()
(知識(shí)點(diǎn):優(yōu)先級(jí) -> 并不是線程按等級(jí)順序來(lái)執(zhí)行完結(jié)束,而是系統(tǒng)處理器優(yōu)先分配處理,并不代表該線程最先處理完(只是會(huì)哭的孩子有奶吃?。?/p>應(yīng)用場(chǎng)景4:在追加多個(gè)處理全部結(jié)束后想執(zhí)行結(jié)束處理 -> dispatch_group()
應(yīng)用場(chǎng)景5:訪問(wèn)數(shù)據(jù)庫(kù)或文件時(shí),為避免數(shù)據(jù)競(jìng)爭(zhēng) -> dispatch_barrier_async()
應(yīng)用場(chǎng)景6:將Block指定次數(shù)的添加到Dispatch queue中 -> dispatch_apply()
應(yīng)用場(chǎng)景7:在大量處理追加到queue中,對(duì)已添加過(guò)未執(zhí)行的處理進(jìn)行管理(掛起/喚醒) -> dispatch_suspend__dispatch_resume()
應(yīng)用場(chǎng)景8:在并行處理更新數(shù)據(jù),會(huì)產(chǎn)生數(shù)據(jù)不一的情況,雖然串行和柵欄函數(shù)(dispatch_barrier_async)也可以解決,但更細(xì)量化處理到任務(wù)中一個(gè)方法調(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];
}
/** 隊(duì)列
- 1.串行(Serial dispatch、Main dispatch)
- 2.并行(Concurrent dispatch)
*/
#pragma mark - Queue
-(void)dispatch_queue{
[self serialQueue];
[self concurrentQueue];
}
-(void)serialQueue{
/**
dispatch_queue_create 生成串行隊(duì)列
- Parameters:
- value1: 自定義
- value2: NULL: 默認(rèn)先進(jìn)先出(FIFO) 即串行
*/
dispatch_queue_t mySerial = dispatch_queue_create("com.example.gcd.MySerialQueue", NULL);
/***
* 異步線程加入串行隊(duì)列 -> 會(huì)開(kāi)辟新線程 但執(zhí)行順序onebyone,有串行隊(duì)列性質(zhì)決定
*/
dispatch_async(mySerial, ^{
NSLog(@"serialQueue_task1");
});
dispatch_async(mySerial, ^{
NSLog(@"serialQueue_task2");
});
// dispatch_release(mySerial);
}
-(void)concurrentQueue{
/**
全局隊(duì)列,并行
@ Parameters:
* value1: 優(yōu)先級(jí) (注意:由于通過(guò)XNU內(nèi)核用于GCD并不能保證時(shí)效性,因此執(zhí)行高優(yōu)先級(jí)只是大致判斷并不精準(zhǔn),在處理的執(zhí)行可有可無(wú)下按優(yōu)先級(jí))
#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)致一個(gè)空返回值
*/
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/***
* 異步線程加入全局隊(duì)列 -> 并行
*/
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)先級(jí)
*/
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");
});
/**
* 追加三個(gè)Block到globel_queue中,等Block中全部執(zhí)行完畢,就會(huì)執(zhí)行 dispatch_get_main_queue中的Block
*/
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Done!");
});
//也可以使用wait, DISPATCH_TIME_FOREVER表示一直等待,也可以是一段時(shí)間內(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ù)生成一個(gè)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開(kāi)始前寫入,將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中,并開(kāi)辟多個(gè)線程
*/
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中,對(duì)已添加過(guò)未執(zhí)行的處理暫停 進(jìn)行管理開(kāi)關(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)建信號(hào)量初始值為1
NSMutableArray *arry = [[NSMutableArray alloc]init];
for (int i = 0; i<1000; i++) {
dispatch_async(queue, ^{
//等待semaphore,計(jì)數(shù)為0時(shí)等待
//一直等待,直到Dispatch_semaphore的計(jì)數(shù)值>=1減一并執(zhí)行
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//-1,
/**
* 由于semphore經(jīng)wait減一,此時(shí)計(jì)數(shù)值為0,可向下進(jìn)行
*/
//訪問(wèn)arry類對(duì)象的線程,只有一個(gè),可以安全訪問(wèn)
[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