隊列
概念

- 按創(chuàng)建主體來劃分
- 默認隊列
- 自定義隊列,自定義隊列通過target指定放到哪個默認隊列,不指定時放在DEFAULT隊列
- 按執(zhí)行線程來劃分:
- main queue 只會在主線程執(zhí)行
- 其他隊列在線程池執(zhí)行(不區(qū)分穿行隊列和并發(fā)隊列)
- 按優(yōu)先級來劃分:
- DISPATCH_QUEUE_PRIORITY_HIGH 2
- DISPATCH_QUEUE_PRIORITY_DEFAULT 0
- DISPATCH_QUEUE_PRIORITY_LOW (-2)
- DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
- 按QoS來劃分:
- QOS_CLASS_USER_INTERACTIVE
- QOS_CLASS_USER_INITIATED
- QOS_CLASS_DEFAULT
- QOS_CLASS_UTILITY
- QOS_CLASS_BACKGROUND
并發(fā)隊列
試驗: 隊列優(yōu)先級與線程的映射
static uint64_t sum = 0;
template <auto tag>
static void stall(void* c)
{
auto start = now();
while (time_us(start) < 100000) sum++;
usleep(10);
os_log(os_log_create("com.yourapp", "stall"), "tag: %{public}d", (int)tag);
}
int main() {
auto g = dispatch_group_create();
auto q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
auto q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
auto q2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
auto q3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
auto start = now();
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q, nullptr, stall<0>);
}
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q1, nullptr, stall<1>);
}
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q2, nullptr, stall<2>);
}
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q3, nullptr, stall<3>);
}
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
printf("total takes %llu us\n", time_us(start));
dispatch_release(q);
}
結論
-
優(yōu)先級是絕對概念,優(yōu)先級高的會先于優(yōu)先級低的先執(zhí)行,內部實現(xiàn)中也能看到實現(xiàn)queue_drain,并不存在用戶態(tài)輪轉選擇
不同優(yōu)先級的隊列對應同一組線程,會在耗盡高優(yōu)先級的任務之后才會消費低優(yōu)先級的任務,上面的例子打印為 0...1...2...3...
-
切換優(yōu)先級時,會改變線程優(yōu)先級,線程優(yōu)先級改變有兩種原因:
-
HIGH和DEFAULT是相對優(yōu)先級,剛開始時線程優(yōu)先級為37,100ms后降到36,每執(zhí)行約10ms再降低1,降低到28后再次回到37,繼續(xù)循環(huán);但是LOW和BACKGROUD優(yōu)先級分別對應固定的線程優(yōu)先級20和4
該機制是用于防止有人濫用高QoS,如果時長時任務,那不該是高QoS
- 線程由執(zhí)行不同的優(yōu)先級隊列時切換
-
HIGH 和DEFAULT會使用大核,其他只使用小核

試驗: 隊列QoS與線程的映射關系
int main() {
auto g = dispatch_group_create();
auto q = dispatch_queue_create("q", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_USER_INTERACTIVE, 0));
auto q1 = dispatch_queue_create("q1", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_USER_INITIATED, 0));
auto q2 = dispatch_queue_create("q2", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_DEFAULT, 0));
auto q3 = dispatch_queue_create("q3", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_UTILITY, 0));
auto q4 = dispatch_queue_create("q4", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0));
auto start = now();
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q4, nullptr, stall<4>);
}
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q3, nullptr, stall<3>);
}
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q2, nullptr, stall<2>);
}
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q1, nullptr, stall<1>);
}
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q, nullptr, stall<0>);
}
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
printf("total takes %llu us\n", time_us(start));
dispatch_release(q);
}
結論
- QoS也是絕對概念,高QoS的會先于低QoS的先執(zhí)行
- 不同QoS的隊列對應同一組線程,會在耗盡高QoS的任務之后才會消費低優(yōu)先級的任務,上面的例子打印為 0...1...2...3...
- 5個QoS對應的線程優(yōu)先級為:47 37 31 20 4
- 切換不同QoS的任務開始執(zhí)行時,會改變線程優(yōu)先級
- 前3個QoS會使用大核,其他只使用小核
串行隊列
試驗:串行隊列和并發(fā)隊列共存時worker的映射關系
auto g = dispatch_group_create();
auto start = now();
{
auto q = dispatch_queue_create("q", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_USER_INTERACTIVE, 0));
auto q1 = dispatch_queue_create("q1", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_USER_INITIATED, 0));
auto q2 = dispatch_queue_create("q2", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_DEFAULT, 0));
auto q3 = dispatch_queue_create("q3", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_UTILITY, 0));
auto q4 = dispatch_queue_create("q4", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0));
auto start = now();
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q4, nullptr, stall<4>);
}
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q3, nullptr, stall<3>);
}
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q2, nullptr, stall<2>);
}
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q1, nullptr, stall<1>);
}
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q, nullptr, stall<0>);
}
}
{
auto q = dispatch_queue_create("q", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0));
auto q1 = dispatch_queue_create("q1", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0));
auto q2 = dispatch_queue_create("q2", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0));
auto q3 = dispatch_queue_create("q3", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0));
auto q4 = dispatch_queue_create("q4", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0));
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q4, nullptr, stall<14>);
}
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q3, nullptr, stall<13>);
}
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q2, nullptr, stall<12>);
}
for (int i = 0; i < 30; i++) {
dispatch_group_async_f(g, q1, nullptr, stall<11>);
}
for (int i = 0; i < 50; i++) {
dispatch_group_async_f(g, q, nullptr, stall<10>);
}
}
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);


246 us創(chuàng)建10個隊列 + 提交300任務,平均任務提交時間不到1us,含喚醒其他線程
- 串行隊列和并發(fā)隊列是否公用線程池
線程喚醒
策略
時延
線程被任務阻塞
如果用戶的任務阻塞了線程池,GCD如何處理
并發(fā)隊列的阻塞
void test2() {
auto g = dispatch_group_create();
auto q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); //("test", DISPATCH_QUEUE_CONCURRENT);
auto q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
auto q2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
auto start = now();
for (int i = 0; i < 100; i++) {
dispatch_group_async_f(g, q, nullptr, stall1);
}
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
for (int i = 0; i < 100; i++) {
dispatch_group_async_f(g, q1, nullptr, stall1);
}
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
for (int i = 0; i < 100; i++) {
dispatch_group_async_f(g, q2, nullptr, stall1);
}
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
printf("total takes %llu us\n", time_us(start));
dispatch_release(q);
}
周期性孤立任務是否觸發(fā)逃生
[圖片上傳失敗...(image-c26c86-1748325119324)]
多進程共享線程池
參考
so逆向
dispatch.dylib
https://f.8tool.club/d.html?d=DB9B53765916340002515929456CF762
dispatch.dylib symbol
https://f.8tool.club/d.html?d=A237C5FF061A5688EAE0FC3AE61FA730
dispatch.dylib symbol
https://f.8tool.club/d.html?d=C6F3CB0F10EA48CAE6C3CE38B7034ED4

