YYDispatchQueuePool原理:
通過維護(hù)一個(gè)上下文結(jié)構(gòu)體胯究,根據(jù)不同QOS優(yōu)先級創(chuàng)建串行隊(duì)列(隊(duì)列數(shù)不超過內(nèi)核)脂凶,因此在每個(gè)串行隊(duì)列下,線程都會(huì)按照先進(jìn)先出的順序去執(zhí)行任務(wù)御滩。通過這樣就可以控制線程數(shù)缴川。
隊(duì)列和線程之間的關(guān)系:
一個(gè)隊(duì)列由一個(gè)或多個(gè)任務(wù)組成,當(dāng)這些任務(wù)要開始執(zhí)行時(shí)额湘,系統(tǒng)會(huì)分別把他們分配到某個(gè)線程上去執(zhí)行卿吐。當(dāng)有多個(gè)系統(tǒng)核心時(shí),為了高效運(yùn)行缩挑,這些核心會(huì)將多個(gè)線程分配到各核心上去執(zhí)行任務(wù)但两。
對于一個(gè)并行隊(duì)列來說,其中的任務(wù)可能被分配到多個(gè)線程中去執(zhí)行供置,即這個(gè)并行隊(duì)列可能對應(yīng)多個(gè)線程谨湘。對于串行隊(duì)列,它每次對應(yīng)一個(gè)線程芥丧,這個(gè)線程可能不變紧阔,可能會(huì)被更換。每一時(shí)刻续担,一個(gè)線程都只能執(zhí)行一個(gè)任務(wù)擅耽。一個(gè)線程也可能是閑置或者掛起的,因此線程存在時(shí)不一定就在執(zhí)行任務(wù)物遇。
iOS8.0之后乖仇,隊(duì)列優(yōu)先級分為5種
- NSQualityOfServiceUserInteractive:最高優(yōu)先級, 用于處理 UI 相關(guān)的任務(wù)
- NSQualityOfServiceUserInitiated:次高優(yōu)先級, 用于執(zhí)行需要立即返回的任務(wù)
- NSQualityOfServiceUtility:普通優(yōu)先級,主要用于不需要立即返回的任務(wù)
- NSQualityOfServiceBackground:后臺(tái)優(yōu)先級询兴,用于處理一些用戶不會(huì)感知的任務(wù)
- NSQualityOfServiceDefault:默認(rèn)優(yōu)先級乃沙,當(dāng)沒有設(shè)置優(yōu)先級的時(shí)候,線程默認(rèn)優(yōu)先級
下面是YYDispatchQueuePool里的處理
static inline qos_class_t NSQualityOfServiceToQOSClass(NSQualityOfService qos) {
switch (qos) {
case NSQualityOfServiceUserInteractive: return QOS_CLASS_USER_INTERACTIVE;
case NSQualityOfServiceUserInitiated: return QOS_CLASS_USER_INITIATED;
case NSQualityOfServiceUtility: return QOS_CLASS_UTILITY;
case NSQualityOfServiceBackground: return QOS_CLASS_BACKGROUND;
case NSQualityOfServiceDefault: return QOS_CLASS_DEFAULT;
default: return QOS_CLASS_UNSPECIFIED;
}
}
YYDispatchContext上下文結(jié)構(gòu)體的定義
typedef struct {
const char *name;
void **queues;
//隊(duì)列數(shù)
uint32_t queueCount;
//計(jì)數(shù)器
int32_t counter;
} YYDispatchContext;
YYDispatchContextCreate 上下文創(chuàng)建
YYDispatchContextRelease 上下文釋放
YYDispatchContextGetQueue 根據(jù)上下文獲取隊(duì)列
YYDispatchContextGetForQOS 根據(jù)QOS優(yōu)先級獲取上下文
YYDispatchContextCreate的實(shí)現(xiàn)
static YYDispatchContext *YYDispatchContextCreate(const char *name,
uint32_t queueCount,
NSQualityOfService qos) {
YYDispatchContext *context = calloc(1, sizeof(YYDispatchContext));
if (!context) return NULL;
context->queues = calloc(queueCount, sizeof(void *));
if (!context->queues) {
free(context);
return NULL;
}
//根據(jù)優(yōu)先級創(chuàng)建隊(duì)列诗舰,控制隊(duì)列數(shù)
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
//iOS8.0之后
dispatch_qos_class_t qosClass = NSQualityOfServiceToQOSClass(qos);
for (NSUInteger i = 0; i < queueCount; i++) {
//這里創(chuàng)建的是serial queue串行隊(duì)列
//不用concurrent queue警儒,主要是因?yàn)椴⑿嘘?duì)列會(huì)讓多個(gè)線程同時(shí)執(zhí)行,會(huì)大量占用CPU資源
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, qosClass, 0);
dispatch_queue_t queue = dispatch_queue_create(name, attr);
context->queues[i] = (__bridge_retained void *)(queue);
}
} else {
//iOS8.0之前
long identifier = NSQualityOfServiceToDispatchPriority(qos);
for (NSUInteger i = 0; i < queueCount; i++) {
dispatch_queue_t queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(queue, dispatch_get_global_queue(identifier, 0));
context->queues[i] = (__bridge_retained void *)(queue);
}
}
context->queueCount = queueCount;
if (name) {
context->name = strdup(name);
}
return context;
}
不使用concurrent queue的原因:避免concurrent queue下眶根,大量線程同時(shí)創(chuàng)建蜀铲、運(yùn)行、銷毀属百,占用主線程的CPU資源记劝,可能會(huì)導(dǎo)致卡頓等問題
下面描述引自YY大神iOS 保持界面流暢的技巧
大量的任務(wù)提交到后臺(tái)隊(duì)列時(shí),某些任務(wù)會(huì)因?yàn)槟承┰虮绘i住導(dǎo)致線程休眠族扰,或者被阻塞厌丑,concurrent queue 隨后會(huì)創(chuàng)建新的線程來執(zhí)行其他任務(wù)钳恕。當(dāng)這種情況變多時(shí),或者 App 中使用了大量 concurrent queue 來執(zhí)行較多任務(wù)時(shí)蹄衷,App 在同一時(shí)刻就會(huì)存在幾十個(gè)線程同時(shí)運(yùn)行忧额、創(chuàng)建、銷毀愧口。CPU 是用時(shí)間片輪轉(zhuǎn)來實(shí)現(xiàn)線程并發(fā)的睦番,盡管 concurrent queue 能控制線程的優(yōu)先級,但當(dāng)大量線程同時(shí)創(chuàng)建運(yùn)行銷毀時(shí)耍属,這些操作仍然會(huì)擠占掉主線程的 CPU 資源托嚣。
YYDispatchContextGetForQOS實(shí)現(xiàn)
static YYDispatchContext *YYDispatchContextGetForQOS(NSQualityOfService qos) {
static YYDispatchContext *context[5] = {0};
switch (qos) {
//最高優(yōu)先級
case NSQualityOfServiceUserInteractive: {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//獲取內(nèi)核數(shù)、這里雖然總體能控制了線程數(shù)厚骗,但不能把CPU發(fā)揮到極致
int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
//最大限制了32個(gè)
count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count;
//創(chuàng)建上下文
context[0] = YYDispatchContextCreate("com.ibireme.yykit.user-interactive", count, qos);
});
return context[0];
} break;
//...more 更多的級別實(shí)現(xiàn)基本都類似
default: {
//默認(rèn)優(yōu)先級
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count;
context[4] = YYDispatchContextCreate("com.ibireme.yykit.default", count, qos);
});
return context[4];
} break;
}
}