队列
概念

- 按创建主体来划分
- 默认队列
- 自定义队列,自定义队列通过target指定放到哪个默认队列,不指定时放在DEFAULT队列
- 按执行线程来划分:
- main queue 只会在主线程执行
- 其他队列在线程池执行(不区分穿行队列和并发队列)
- 按优先级来划分:
- 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
并发队列
试验: 队列优先级与线程的映射
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);
}
结论
-
优先级是绝对概念,优先级高的会先于优先级低的先执行,内部实现中也能看到实现queue_drain,并不存在用户态轮转选择
不同优先级的队列对应同一组线程,会在耗尽高优先级的任务之后才会消费低优先级的任务,上面的例子打印为 0...1...2...3...
-
切换优先级时,会改变线程优先级,线程优先级改变有两种原因:
-
HIGH和DEFAULT是相对优先级,刚开始时线程优先级为37,100ms后降到36,每执行约10ms再降低1,降低到28后再次回到37,继续循环;但是LOW和BACKGROUD优先级分别对应固定的线程优先级20和4
该机制是用于防止有人滥用高QoS,如果时长时任务,那不该是高QoS
- 线程由执行不同的优先级队列时切换
-
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的先执行
- 不同QoS的队列对应同一组线程,会在耗尽高QoS的任务之后才会消费低优先级的任务,上面的例子打印为 0...1...2...3...
- 5个QoS对应的线程优先级为:47 37 31 20 4
- 切换不同QoS的任务开始执行时,会改变线程优先级
- 前3个QoS会使用大核,其他只使用小核
串行队列
试验:串行队列和并发队列共存时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创建10个队列 + 提交300任务,平均任务提交时间不到1us,含唤醒其他线程
- 串行队列和并发队列是否公用线程池
线程唤醒
策略
时延
线程被任务阻塞
如果用户的任务阻塞了线程池,GCD如何处理
并发队列的阻塞
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);
}
周期性孤立任务是否触发逃生
[图片上传失败...(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

