GCD多線程基礎(chǔ)知識(shí)
Serial Dispatch Queue 串行隊(duì)列
Concurrent Dispatch Queue 并行隊(duì)列
GCD創(chuàng)建隊(duì)列
// 創(chuàng)建串行隊(duì)列
dispatch_queue_create("dispatchSign", DISPATCH_QUEUE_SERIAL);
// 創(chuàng)建并行隊(duì)列
dispatch_queue_create("dispatchSign", DISPATCH_QUEUE_CONCURRENT);
"dispatchSign" 為隊(duì)列標(biāo)識(shí),const char類型字符串,亦為控制臺(tái)輸入的名稱
異步和同步執(zhí)行
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"同步在主線程中執(zhí)行");
});
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"異步在主線程中執(zhí)行");
});
系統(tǒng)提供的隊(duì)列
取得主隊(duì)列
dispatch_get_main_queue()
主線程是一個(gè)同步的串行隊(duì)列,亦稱主線程
取得global隊(duì)列
// global 默認(rèn)優(yōu)先級(jí)
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
優(yōu)先級(jí)參數(shù)列表:
// 最高優(yōu)先級(jí)
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
// 普通優(yōu)先級(jí)
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
// 低優(yōu)先級(jí)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
// 最低優(yōu)先級(jí),后臺(tái)執(zhí)行
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
global隊(duì)列是系統(tǒng)提供的全局型的,并行隊(duì)列
同一個(gè)優(yōu)先級(jí)的隊(duì)列,先調(diào)用的任務(wù),就會(huì)先執(zhí)行
多線程的帶來的問題
競爭資源:
兩個(gè)線程,同時(shí)訪問同一個(gè)資源,會(huì)造成崩潰的問題
性能消耗:
線程之間的切換,稱為切換上下文環(huán)境
iPhone一直保持著大核心,少核心的CPU封裝原則
一盒CPU同一個(gè)時(shí)間短,只能處理一個(gè)任務(wù)
過多的線程會(huì)造成CPU核心反復(fù)的切換上下文環(huán)境
如果線程過多,上下文切換會(huì)非常消耗硬件性能
應(yīng)對(duì)方案:
資源競爭加鎖: 自旋鎖, 互斥鎖
性能消耗: 少生成隊(duì)列,必要時(shí),生成全局變量或靜態(tài)變量的隊(duì)列,減少上下文環(huán)境的切換
龐大任務(wù)下,對(duì)處理量進(jìn)行切割:
由于一個(gè)任務(wù)只能在一核CPU中運(yùn)行
對(duì)任務(wù)進(jìn)行切割,分成多個(gè)任務(wù),組成多個(gè)串行隊(duì)列或放入并行隊(duì)列中執(zhí)行
在一定程度上,會(huì)更多的調(diào)動(dòng)CPU資源
iOS 6以后GCD才支持ARC
iOS 6 以前需要手動(dòng)釋放
dispatch_release();
手動(dòng)retain
dispatch_retain();
隊(duì)列和線程的對(duì)應(yīng)關(guān)系
串行隊(duì)列,使用一個(gè)線程
串行隊(duì)列 -> 線程
并行隊(duì)列,可能使用多個(gè)線程
并行隊(duì)列:
任務(wù)1 -> 線程1
任務(wù)2 -> 線程2
任務(wù)3 -> 線程3
串行隊(duì)列中,隊(duì)列與線程1對(duì)1,所以隊(duì)列=線程
并行隊(duì)列中,隊(duì)列與線程1對(duì)多,所以隊(duì)列!=線程
例如:
主線程=主隊(duì)列 dispatch_get_main_queue()
但是如果是并行隊(duì)列,則不可將隊(duì)列稱為線程
調(diào)整隊(duì)列的優(yōu)先級(jí)
// global隊(duì)列可在取得時(shí),生成對(duì)應(yīng)的優(yōu)先級(jí)
dispatch_get_global_queue(DISPATCH_TARGET_QUEUE_DEFAULT, 0);
自行創(chuàng)建的隊(duì)列就需要 dispatch_set_target_queue函數(shù)進(jìn)行調(diào)整
// 將queue1的優(yōu)先級(jí),變?yōu)榕cqueue2相同
// 參照
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 被改變優(yōu)先級(jí)的隊(duì)列
dispatch_queue_t queue2 = dispatch_queue_create("dispatchSign", DISPATCH_QUEUE_SERIAL);
// 改變優(yōu)先級(jí)函數(shù)
dispatch_set_target_queue(queue1, queue2);
此外還有使串行隊(duì)列順序執(zhí)行的功能,
原理為: 改變成同一個(gè)global隊(duì)列相同的優(yōu)先級(jí), 然后哪個(gè)串行隊(duì)列先調(diào)用,哪個(gè)就會(huì)先執(zhí)行
dispatch_barrier
在普通任務(wù)執(zhí)行完成之后,再將任務(wù)插入隊(duì)列
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
NSLog(@"1");
});
dispatch_barrier_sync(concurrentQueue, ^{
NSLog(@"3");
});
dispatch_async(concurrentQueue, ^{
NSLog(@"2");
});
先輸出1,2 最后再輸入3
dispatch_apply
在隊(duì)列中,執(zhí)行10次,block中的任務(wù)
dispatch_apply 會(huì)鎖死當(dāng)前代碼運(yùn)行的線程
相當(dāng)于在執(zhí)行任務(wù)的時(shí)候用async,在執(zhí)行的最后加入了group_wait
// 并行隊(duì)列無順序,串行隊(duì)列有順序
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, globalQueue, ^(size_t index) {
NSLog(@"執(zhí)行次數(shù)%zd",index);
});
NSLog(@"完成");
在globalQueue隊(duì)列中,分別打印,執(zhí)行次數(shù)1~10.最后打印完成
dispatch_suspend暫停隊(duì)列, dispatch_resume重新啟動(dòng)隊(duì)列
dispatch_suspend()
dispatch_resume()