前言
Linux 内核支持多种调度策略,根据不同的任务需求和实时性要求,可分为 普通调度策略 和 实时调度策略。观复君本次讲解以Linux系统为例,希望能给大家的工作带来一些启发。
Linux任务调度策略
普通调度策略(非实时任务)
SCHED_OTHER
(完全公平调度器,CFS)
-
类型:默认策略,面向普通优先级任务。
-
特点:
-
基于时间片轮转,动态分配 CPU 时间,确保任务间的公平性。
-
使用 虚拟运行时间(vruntime) 决定任务调度顺序。
-
支持 优先级(nice值)(范围:
-20
(最高)到19
(最低))。
-
-
适用场景:大多数普通进程(如用户应用程序、后台服务)。
SCHED_BATCH
-
类型:优化批处理任务。
-
特点:
-
类似
SCHED_OTHER
,但减少交互式任务的优先级,适合长时间运行的批处理作业。 -
任务倾向于一次性占用较长 CPU 时间片,减少上下文切换开销。
-
-
适用场景:非交互式计算密集型任务(如编译、数据分析)。
SCHED_IDLE
-
类型:最低优先级任务。
-
特点:
-
仅在系统空闲时运行,优先级低于所有其他策略。
-
不占用公平调度的时间配额。
-
-
适用场景:极低优先级的后台任务(如系统监控探针)。
实时调度策略
SCHED_FIFO
(先进先出)
-
类型:严格实时策略。
-
特点:
-
任务一旦获得 CPU,会一直运行直到主动释放(如阻塞、调用
sched_yield
)或被更高优先级的实时任务抢占。 -
无时间片限制,除非被抢占。
-
优先级范围:
1
(最低)到99
(最高)(数值越大优先级越高)。
-
-
适用场景:需要确定性和低延迟的实时任务(如硬件控制)。
SCHED_RR
(轮转调度)
-
类型:实时策略,带时间片轮转。
-
特点:
-
类似
SCHED_FIFO
,但每个任务有固定时间片(默认 100ms,可通过sched_rr_timeslice_ms
调整)。 -
时间片耗尽后,任务被移到同优先级队列末尾,允许其他同优先级任务运行。
-
优先级范围:
1
到99
。
-
-
适用场景:需要共享 CPU 的同优先级实时任务(如音视频处理)。
SCHED_DEADLINE
(截止时间优先)
-
类型:基于截止时间的实时策略(Linux 3.14+ 引入)。
-
特点:
-
任务需声明三个参数:运行时间(
runtime
)、截止时间(deadline
)、周期(period
)。 -
调度器确保任务在截止时间前完成指定运行时间,否则视为超时。
-
优先级动态计算,截止时间越近的任务优先级越高。
-
-
适用场景:严格周期性实时任务(如机器人控制、传感器采样)。
调度策略对比
策略 | 类型 | 时间片 | 抢占规则 | 优先级范围 | 典型场景 |
---|---|---|---|---|---|
SCHED_OTHER | 普通 | 动态调整 | 公平调度 | -20 到 19 | 普通应用程序 |
SCHED_BATCH | 普通 | 较长 | 低交互性优化 | 同 SCHED_OTHER | 批处理任务 |
SCHED_IDLE | 普通 | 无限制 | 仅空闲时运行 | 最低 | 后台监控 |
SCHED_FIFO | 实时 | 无 | 高优先级抢占 | 1 到 99 | 硬件中断处理 |
SCHED_RR | 实时 | 固定 | 同优先级轮转 | 1 到 99 | 多任务实时协作 |
SCHED_DEADLINE | 实时 | 动态 | 截止时间驱动 | 动态计算 | 周期性实时任务 |
nice值与优先级的异同
心细的朋友可能已经关注到SCHED_OTHER
的调度策略是通过nice值来表示的,它的含义与其他调度策略(如实时策略)不同。
以下是对 SCHED_OTHER
优先级(nice值)的详细解释。
1. SCHED_OTHER
优先级的特点
-
优先级范围:
nice
值的范围是 -20 到 19(数值越小,优先级越高)。 -
默认值:新进程默认的
nice
值为 0。 -
作用方式:
-
nice
值不直接决定绝对优先级,而是影响进程在 完全公平调度器(CFS) 中的 CPU 时间权重。 -
值越小(如
-20
),进程的权重越高,分配的 CPU 时间比例越大。 -
值越大(如
19
),权重越低,分配的 CPU 时间比例越小。
-
2. 关键规则
nice 值 | 含义 |
---|---|
-20 | 最高优先级(进程将获得比其他进程更多的 CPU 时间) |
0 | 默认优先级(与其他 nice=0 的进程平等竞争 CPU 时间) |
19 | 最低优先级(进程仅在其他高优先级进程不需要 CPU 时才运行) |
示例:
-
如果进程 A 的
nice=-10
,进程 B 的nice=10
,则 A 的 CPU 时间权重远高于 B。 -
这种差异在系统负载较高时更明显,但在空闲系统中可能表现相似。
3. nice
值与实时优先级的区别
-
SCHED_OTHER
(普通进程):-
优先级通过
nice
值调整(范围:-20 到 19)。 -
数值越小,优先级越高。
-
-
实时策略(
SCHED_FIFO
/SCHED_RR
):-
优先级通过
sched_priority
调整(范围:1 到 99)。 -
数值越大,优先级越高。
-
⚠️ 注意:实时策略的进程优先级(1-99)永远高于普通策略(SCHED_OTHER
),即使普通进程的 nice=-20
。
进程优先级调整
系统支持调度策略查看
chrt
是 Linux 中用于操作调度策略的工具,直接运行 chrt
命令会显示支持的策略列表:
chrt -h
输出示例(J3):
如果输出中没有某个策略(如 SCHED_DEADLINE
),则内核可能未启用该策略支持。
调整普通进程的nice值
查看进程的nice值
ps -eo pid,ni,comm | grep <进程名>
指令方式
修改已运行进程的 nice
值
# 语法:renice -n <目标值> -p <PID>
# 示例:将 PID=1234 的进程的 nice 值设为 -5
sudo renice -n -5 -p 1234 # 需要 root 权限
# 示例:将 PID=5678 的进程的 nice 值设为 10
renice -n 10 -p 5678 # 普通用户可运行(仅能降低优先级)
启动新进程时指定 nice
值
# 语法:nice -n <增量> <命令>
# 示例:启动一个高优先级进程(nice=-10)
sudo nice -n -10 ./my_program # 需要 root 权限(降低 nice 值)
# 示例:启动一个低优先级进程(nice=15)
nice -n 15 ./my_program # 普通用户可直接运行(增大 nice 值)
-
规则:
-
-n
后的数值是相对于默认值(0
)的增量。例如:-
nice -n -10
→ 最终nice=-10
(更高优先级)。 -
nice -n 5
→ 最终nice=5
(更低优先级)。
-
-
普通用户只能降低优先级(增大
nice
值),提高优先级(减小nice
值)需要 root 权限。
-
代码方式
使用 setpriority
函数动态调整优先级。
#include <stdio.h>
#include <sys/resource.h>
int main() {
int new_nice = -10; // 设置更高的优先级(需要 root 权限)
// 设置当前进程的 nice 值
if (setpriority(PRIO_PROCESS, 0, new_nice) == -1) {
perror("setpriority failed");
return 1;
}
printf("当前进程的 nice 值已设置为: %d\n", new_nice);
return 0;
}
编译运行:
gcc set_nice.c -o set_nice
sudo ./set_nice # 需要 root 权限(因为降低 nice 值)
调整实时进程的优先级
查看进程的调度策略和优先级
not0397@DZ-NOT-0397:~$ chrt -p 2643077
pid 2643077 当前的调度策略︰ SCHED_OTHER
pid 2643077 的当前调度优先级:0
指令方式
1. 启动新进程时指定调度策略和优先级
# 语法:chrt [选项] <优先级> <命令>
# 示例:以 SCHED_FIFO 策略、优先级 90 启动进程
sudo chrt -f 90 ./my_realtime_task # -f 表示 SCHED_FIFO
# 示例:以 SCHED_RR 策略、优先级 50 启动进程
sudo chrt -r 50 ./my_realtime_task # -r 表示 SCHED_RR
# 示例:以 SCHED_DEADLINE 策略启动(需额外参数)
sudo chrt -d --sched-runtime 10000000 --sched-deadline 20000000 --sched-period 20000000 0 ./my_deadline_task
-
选项:
-
-f
:SCHED_FIFO
(严格实时)。 -
-r
:SCHED_RR
(带时间片轮转的实时)。 -
-d
:SCHED_DEADLINE
(需指定运行时间、截止时间和周期,单位:纳秒)。
-
2. 修改已运行进程的调度策略和优先级
# 语法:chrt -p [选项] <优先级> <PID>
# 示例:将 PID=1234 的进程设为 SCHED_FIFO,优先级 80
sudo chrt -f -p 80 1234
# 示例:将 PID=5678 的进程设为 SCHED_RR,优先级 60
sudo chrt -r -p 60 5678
代码方式
实时策略的优先级通过 sched_priority
字段设置(范围:1
(最低)到 99
(最高))。
代码示例:使用 sched_setscheduler
函数设置策略和优先级。
#include <stdio.h>
#include <sched.h>
#include <stdlib.h>
int main() {
struct sched_param param;
int policy = SCHED_FIFO; // 调度策略
int priority = 80; // 实时优先级(1-99)
// 设置优先级参数
param.sched_priority = priority;
// 设置调度策略和优先级
if (sched_setscheduler(0, policy, ¶m) == -1) {
perror("sched_setscheduler failed");
exit(EXIT_FAILURE);
}
printf("当前进程已设置为 SCHED_FIFO,优先级: %d\n", priority);
return 0;
}
注意事项
1. 权限要求
操作 | 所需权限 |
---|---|
提高 nice 值(降低优先级) | 普通用户可直接操作 |
降低 nice 值(提高优先级) | 需要 root 权限 |
设置实时策略(SCHED_FIFO 等) | 需要 root 权限或 CAP_SYS_NICE 能力 |
2. 实时策略的风险
-
CPU 独占:高优先级
SCHED_FIFO
任务可能长时间占用 CPU,导致系统无响应。
解决方案:合理分配优先级,或结合SCHED_RR
使用时间片轮转。
3. 调度策略的兼容性
-
SCHED_DEADLINE
:需内核 ≥3.14 并启用CONFIG_SCHED_DEADLINE
,且需指定runtime
、deadline
、period
参数。 -
实时内核优化:在 PREEMPT RT 补丁的内核(如地平线 J3 系统)中,实时任务响应更快。