第四十章:优先级
结丹中期涉及内核源码:
一
林小源在调度仙子的指导下,开始研究优先级的体系。
他站在竞技场的边缘,面前竖着一面巨大的石碑。石碑上刻着三个维度的数字,从上到下排列,像三重阶梯。
"三种优先级,"调度仙子站在石碑旁,"第一种是 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"。
/*
* 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");#include <stdio.h>
/*
* 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];
}
int main() {
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");
return 0;
}道藏笔记
内核启示
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 值、权重和调度倾斜联系起来,核心围绕的是任务的哪一种调度属性?