队列优先级和任务执行顺序的关系
实验代码1 :相同数量任务,低优先级队列先提交
队列优先级从低到高,每个队列入队若干个任务(上一个队列入队完成后,才向下一个入队),查看任务执行情况
void queue_concurrent()
{
os_signpost_id_t __spid = os_signpost_id_make_with_pointer(LOG_PERF, (void*)now_ns);
os_signpost_interval_begin(LOG_PERF, __spid, "queue_concurrent", "");
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_ns();
for (int i = 0; i < task_count; i++) {
dispatch_group_async_f(g, q4, nullptr, sleep_10ms);
}
for (int i = 0; i < task_count; i++) {
dispatch_group_async_f(g, q3, nullptr, sleep_11ms);
}
for (int i = 0; i < task_count; i++) {
dispatch_group_async_f(g, q2, nullptr, sleep_12ms);
}
for (int i = 0; i < task_count; i++) {
dispatch_group_async_f(g, q1, nullptr, sleep_13ms);
}
for (int i = 0; i < task_count; i++) {
dispatch_group_async_f(g, q, nullptr, sleep_14ms);
}
os_signpost_interval_end(LOG_PERF, __spid, "queue_concurrent", "");
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
printf("total takes %llu ms\n", now_ns() - start);
}
任务提交的队列所处的优先级顺序由低到高:
QOS_CLASS_BACKGROUND
,QOS_CLASS_UTILITY
,QOS_CLASS_DEFAULT
,QOS_CLASS_USER_INITIATED
,QOS_CLASS_USER_INTERACTIVE
图里面的任务,最下面却先执行完成的是高优先级QOS_CLASS_USER_INTERACTIVE
,最上面却最后执行完成的是低优先级QOS_CLASS_BACKGROUND
少量任务(task_count = 50)
iPhone7,iOS 15.7
iPad mini 5,iOS 18.5
iPhone 14 Pro Max,iOS 26
大量任务(task_count = 500)
iPhone7,iOS 15.7
iPad mini 5,iOS 18.5
iPhone 14 Pro Max,iOS 26
附录:辅助代码
#import <Foundation/Foundation.h>
#include <chrono>
#include <os/signpost.h>
#include <mach/mach_time.h>
static inline long long now_ns(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec;
}
static os_log_t LOG_PERF = os_log_create("com.ufogxl.GCDTest", "Custom");
#define PERF_BEGIN(log, spid, ptr, name) \
spid = os_signpost_id_make_with_pointer(log, (ptr)); \
os_signpost_interval_begin(log, spid, (name), "");
#define PERF_END(log, spid, name) \
os_signpost_interval_end(log, spid, (name), "");
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
// printf("sleep for " TOSTRING(ms) " ms\n");
#define DEFINE_SLEEP_MS_FN(name, ms) \
__attribute__((used)) \
void name(void*_) { \
os_signpost_id_t spid; \
uint64_t now_ns = mach_absolute_time(); \
PERF_BEGIN(LOG_PERF, spid, (void*)now_ns, #name); \
(void)_; \
const uint64_t _ms = (ms); \
mach_timebase_info_data_t info; \
mach_timebase_info(&info); \
uint64_t ns = _ms * 1000000L; \
uint64_t ticks = ns * info.denom / info.numer; \
mach_wait_until(now_ns + ticks); \
PERF_END(LOG_PERF, spid, #name); \
}
//#define DEFINE_SLEEP_MS_FN(name, ms) \
//void name(void*_) { \
// printf("sleep for " TOSTRING(ms) " ms\n"); \
//}
DEFINE_SLEEP_MS_FN(sleep_4ms, 4)
DEFINE_SLEEP_MS_FN(sleep_3ms, 3)
DEFINE_SLEEP_MS_FN(sleep_2ms, 2)
DEFINE_SLEEP_MS_FN(sleep_1ms, 1)
DEFINE_SLEEP_MS_FN(sleep_0ms, 0)
DEFINE_SLEEP_MS_FN(sleep_14ms, 14)
DEFINE_SLEEP_MS_FN(sleep_13ms, 13)
DEFINE_SLEEP_MS_FN(sleep_12ms, 12)
DEFINE_SLEEP_MS_FN(sleep_11ms, 11)
DEFINE_SLEEP_MS_FN(sleep_10ms, 10)