Skip to content

第四十章:优先级

结丹中期

涉及内核源码:

林小源在调度仙子的指导下,开始研究优先级的体系。

他站在竞技场的边缘,面前竖着一面巨大的石碑。石碑上刻着三个维度的数字,从上到下排列,像三重阶梯。

"三种优先级,"调度仙子站在石碑旁,"第一种是 nice 值,用户态可见,范围从 -20 到 19。值越小,优先级越高。第二种是内核 prio,范围从 0 到 139。第三种是 rt_priority,实时进程的优先级,范围从 1 到 99。"

林小源看着石碑上的数字:"它们之间有什么关系?"

调度仙子指向石碑的中间区域:"普通进程——也就是 CFS 管理的进程——prio = 120 + nice。所以 nice -20 对应 prio 100,nice 0 对应 prio 120,nice 19 对应 prio 139。"

"那实时进程呢?"

"实时进程的 prio = 99 - rt_priority。rt_priority 99 对应 prio 0——最高优先级。rt_priority 1 对应 prio 98。"

林小源皱眉:"实时进程的 prio 范围是 0 到 98,普通进程是 100 到 139。所以实时进程总是优先于普通进程?"

"对。"调度仙子说,"这是设计的意图。实时进程需要确定性的响应时间——它们不能和普通进程公平竞争。"

林小源在石碑前研究了很久,发现了权重表的秘密。

"nice 值每增加 1,权重大约减少 10%。"他指着石碑上的数字说。

调度仙子点头:"权重表是一个等比数列。nice 0 的权重是 1024,nice 1 的权重是 820,大约是 1024 的 0.8 倍。这个比例保证了 nice 值的差异在 CPU 时间分配上的感知一致性。"

"感知一致性?"

"意思是,"调度仙子解释道,"无论你的 nice 值是多少,从 nice N 到 nice N+1,你感受到的 CPU 时间减少比例是相同的——大约 10%。这对用户来说是'公平'的感知。"

林小源想了想:"所以 nice 值的设计考虑了人对'公平'的感知,而不仅仅是数学上的公平?"

"可以这么理解。"调度仙子说,"内核的很多设计都不仅仅是技术问题,还涉及人类的感知和习惯。"

"还有一个细节,"她补充道,"用户态进程可以通过 系统调用修改自己的 nice 值,但只能增加——也就是降低优先级。如果想减少 nice 值——提高优先级——需要 root 权限。"

"降低自己是自由的,提高自己需要特权。"林小源喃喃道。

"这是安全设计。"调度仙子说,"如果任何进程都能提高自己的优先级,恶意进程就能独占 CPU。只有 root 才能赋予进程更高的优先级。"

林小源在石碑前站了很久,看着那些不断跳动的数字。

"优先级高,就一定能获得更多 CPU 时间吗?"他问。

调度仙子摇头:"不一定。nice 值只在'竞争'时才起作用。如果一个 nice -20 的进程大部分时间在睡眠中等待 I/O,它消耗的 CPU 时间可能比一个 nice 19 的批处理任务还少。"

"所以优先级不是'保证',而是'竞争时的优势'。"

"对。"调度仙子说,"当多个进程同时争抢 CPU 时,优先级高的进程更有可能被选中。但如果优先级高的进程主动让出 CPU——比如等待 I/O——优先级低的进程就能获得 CPU 时间。"

林小源想起了自己在炼气期的经历:外门弟子在秘境试炼中有优先权,但如果外门弟子选择休息,内门弟子仍然可以进入秘境。优先级不是"独占",而是"优先"。

"还有一种情况,"调度仙子说,"某些进程的 nice 值被设置得很低,但它们的实际 CPU 使用率并不高。这是因为 CFS 的公平性保证——即使 nice 值很低,如果进程大部分时间在睡眠中,它也不会消耗太多 CPU 时间。"

林小源点了点头。他终于理解了优先级的本质:它不是"保证你获得多少 CPU",而是"当 CPU 竞争激烈时,谁先获得 CPU"。


c
/*
 * Linux 优先级的三种表示:
 *
 * 1. nice 值: -20 ~ 19
 *    用户态可见,值越小优先级越高
 *    普通进程使用 nice 值
 *
 * 2. 内核 prio: 0 ~ 139
 *    0 ~ 99:  实时进程
 *    100 ~ 139: 普通进程 (100 + nice)
 *
 * 3. rt_priority: 1 ~ 99
 *    实时进程的优先级
 *    值越大优先级越高
 *
 * 转换关系:
 *   普通进程: prio = 120 + nice
 *   实时进程: prio = 99 - rt_priority
 */

#define MAX_RT_PRIO 100
#define DEFAULT_PRIO 120

/* nice 值到权重的映射 */
int nice_to_weight(int nice) {
    static int weights[] = {
        88761, 71755, 56483, 46273, 36291,
        29154, 23254, 18705, 14949, 11916,
         9548,  7620,  6100,  4904,  3906,
         3121,  2501,  1991,  1586,  1277,
         1024,   820,   655,   526,   423,
          335,   272,   215,   172,   137,
          110,    87,    70,    56,    45,
           36,    29,    23,    18,    15,
    };
    return weights[nice + 20];
}

printf("=== 优先级的层次 ===\n\n");

printf("--- 普通进程的优先级 ---\n");
printf("%-6s %-8s %-10s %-12s\n", "nice", "prio", "权重", "调度类");
printf("%-6s %-8s %-10s %-12s\n", "---", "---", "---", "---");

int nices[] = { -20, -10, 0, 5, 10, 19 };
int nr = sizeof(nices) / sizeof(nices[0]);

for (int i = 0; i < nr; i++) {
    int nice = nices[i];
    int prio = DEFAULT_PRIO + nice;
    int weight = nice_to_weight(nice);
    printf("%-6d %-8d %-10d %-12s\n",
           nice, prio, weight, "CFS (fair)");
}

printf("\n--- 实时进程的优先级 ---\n");
printf("%-14s %-6s %-12s\n", "rt_priority", "prio", "调度类");
printf("%-14s %-6s %-12s\n", "---", "---", "---");

int rt_prios[] = { 99, 50, 1 };
int nr_rt = sizeof(rt_prios) / sizeof(rt_prios[0]);

for (int i = 0; i < nr_rt; i++) {
    int rt = rt_prios[i];
    int prio = MAX_RT_PRIO - 1 - rt;
    printf("%-14d %-6d %-12s\n", rt, prio, "RT (FIFO/RR)");
}

printf("\n--- 优先级的转换 ---\n");
printf("普通进程:\n");
printf("  prio = 120 + nice\n");
printf("  nice -20 → prio 100 (最高)\n");
printf("  nice  0  → prio 120 (默认)\n");
printf("  nice  19 → prio 139 (最低)\n\n");
printf("实时进程:\n");
printf("  prio = 99 - rt_priority\n");
printf("  rt_priority 99 → prio 0 (最高)\n");
printf("  rt_priority 1  → prio 98 (最低)\n");

printf("\n--- 调度类的优先级 ---\n");
printf("stop > dl > rt > fair > idle\n");
printf("  stop:  不可抢占,用于 CPU hotplug\n");
printf("  dl:    Deadline 调度器\n");
printf("  rt:    实时调度器 (FIFO/RR)\n");
printf("  fair:  CFS (普通进程)\n");
printf("  idle:  idle 进程\n");

道藏笔记

内核启示

Linux 有三种优先级表示。

nice 值(用户态):

  • 范围:-20 ~ 19
  • 值越小优先级越高
  • 每增加 1,CPU 时间约减少 10%
  • 只有 root 能降低 nice 值(提高优先级)

内核 prio:

  • 范围:0 ~ 139
  • 0 ~ 99:实时进程
  • 100 ~ 139:普通进程(prio = 120 + nice

rt_priority(实时进程):

  • 范围:1 ~ 99
  • 值越大优先级越高
  • prio = 99 - rt_priority

权重表(sched_prio_to_weight[]):

  • 等比数列,保证 nice 值的差异在 CPU 时间上感知一致
  • nice 0 = 1024(基准)
  • nice -20 = 88761
  • nice 19 = 15

优先级不是"保证",是"竞争"时的优势。


破关试炼

优先级之试

本章把 nice 值、权重和调度倾斜联系起来,核心围绕的是任务的哪一种调度属性?

答对后才能继续滑动和进入下一章。

以修仙之名,悟内核之道