在 Linux 系统中,除了常见的 SCHED_FIFO
、SCHED_RR
和 SCHED_OTHER
调度策略外,还有 SCHED_BATCH
、SCHED_DEADLINE
和 SCHED_IDLE
等调度策略,它们各自适用于不同的场景。以下是对这些调度策略的介绍以及如何更改它们的方法:
介绍
1. SCHED_BATCH
- 特点:
SCHED_BATCH
是一种用于批处理任务的调度策略。它适用于那些对实时性要求不高但需要长时间运行的任务,例如后台计算任务。与SCHED_OTHER
不同,SCHED_BATCH
会减少进程的调度频率,尽量让进程一次性运行更长时间,从而提高效率。 - 适用场景:适合批处理任务,如科学计算、数据处理等。
2. SCHED_DEADLINE
- 特点:
SCHED_DEADLINE
是一种实时调度策略,适用于对时间敏感的任务。它通过三个参数(运行时间、周期、截止时间)来管理任务的执行。例如,一个任务可能需要在每 100ms 的周期内运行 10ms,并且必须在 90ms 内完成。 - 适用场景:适用于需要严格时间约束的实时任务,如工业自动化、音频处理等。
3. SCHED_IDLE
- 特点:
SCHED_IDLE
是一种低优先级的调度策略,适用于那些只有在系统空闲时才运行的任务。它确保这些任务不会干扰其他更高优先级的任务。 - 适用场景:适合低优先级的后台任务,如磁盘清理工具。
4. SCHED_FIFO
- 特点:
SCHED_FIFO
是一种实时调度策略,采用先进先出的方式。一旦进程获得 CPU,它会一直运行,直到主动放弃 CPU 或被更高优先级的进程抢占。 - 适用场景:适用于对实时性要求极高的任务,如音视频处理。
5. SCHED_RR
- 特点:
SCHED_RR
是一种带有时间片的实时调度策略。它与SCHED_FIFO
类似,但在时间片耗尽后会释放 CPU。 - 适用场景:适用于需要多个实时任务公平共享 CPU 的场景。
6. SCHED_OTHER
- 特点:
SCHED_OTHER
是 Linux 系统中默认的调度策略,基于完全公平调度器(CFS)。它通过动态优先级和时间片来平衡系统中所有进程的 CPU 时间。 - 适用场景:适用于大多数普通用户程序和后台服务。
通过命令配置更改进程调度策略的方法
1. 使用 chrt
命令
chrt
是一个常用的命令行工具,用于设置或查看进程的调度策略和优先级。
-
设置调度策略:
-
设置为
SCHED_FIFO
:chrt -f -p <优先级> <进程ID>
例如,将进程ID为1234的调度策略设置为
SCHED_FIFO
,优先级为99:chrt -f -p 99 1234
-
设置为
SCHED_RR
:chrt -r -p <优先级> <进程ID>
例如,将进程ID为1234的调度策略设置为
SCHED_RR
,优先级为50:chrt -r -p 50 1234
-
设置为
SCHED_OTHER
(默认调度策略):chrt -o -p <进程ID>
-
-
启动时指定调度策略: 如果需要在启动进程时指定调度策略,可以直接在
chrt
命令中指定:chrt -f 99 /path/to/your/application
2. 使用 systemd
配置文件
对于通过 systemd
管理的服务,可以在服务的配置文件中设置调度策略。
-
在服务的
[Service]
部分添加以下配置:[Service] ExecStart=/path/to/your/service CPUSchedulingPolicy=fifo # 或 rr/other CPUSchedulingPriority=99 # 对于实时策略,指定优先级
-
示例(
SCHED_FIFO
):[Unit] Description=My Service [Service] ExecStart=/path/to/my/service CPUSchedulingPolicy=fifo CPUSchedulingPriority=99 [Install] WantedBy=default.target
-
修改配置后,需要重新加载
systemd
配置并重启服务:systemctl daemon-reload systemctl restart your-service-name
3. 内核参数调整
虽然内核参数主要用于调整调度器的行为,而不是直接更改调度策略,但某些参数可能会影响调度策略的效果。
-
查看当前调度策略: 使用
ps
命令查看进程的调度策略:ps -eo pid,comm,policy
-
调整实时进程的运行时间:
-
sched_rt_period_us
:实时进程的时间周期(默认1秒)。 -
sched_rt_runtime_us
:实时进程在每个周期内的最大运行时间(默认0.95秒)。 -
调整方法:
echo 1000000 > /proc/sys/kernel/sched_rt_period_us echo 950000 > /proc/sys/kernel/sched_rt_runtime_us
-
-
调整
SCHED_RR
的时间片:-
sched_rr_timeslice_ms
:设置SCHED_RR
的时间片大小(默认100ms)。 -
调整方法:
echo 100 > /proc/sys/kernel/sched_rr_timeslice_ms
-
注意事项
- 更改调度策略通常需要
root
权限。 - 实时调度策略(
SCHED_FIFO
和SCHED_RR
)的优先级范围是1(最低)到99(最高),默认调度策略(SCHED_OTHER
)不支持优先级设置。 - 在生产环境中,建议谨慎使用实时调度策略,因为它们可能对系统资源分配产生较大影响。
通过编程的方式更改进程调度策略
在 Linux 系统中,可以通过 sched_setattr
系统调用设置进程的调度策略和相关参数。以下是一个使用 sched_setattr
的示例代码,展示如何设置不同的调度策略(如 SCHED_FIFO
、SCHED_RR
、SCHED_DEADLINE
等)。
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> // 包含 uint32_t 和 uint64_t 的定义
#include <linux/sched.h>
#include <unistd.h>
#include <errno.h>
//sched_setattr 和 struct sched_attr 的定义在某些情况下可能未被 glibc 包含,
//因此需要手动定义这些内容
// 手动定义 sched_attr 结构体
struct sched_attr {
uint32_t size;
uint32_t sched_policy;
uint64_t sched_flags;
int32_t sched_nice;
uint32_t sched_priority;
uint64_t sched_runtime;
uint64_t sched_deadline;
uint64_t sched_period;
};
// 手动定义系统调用号(x86_64 架构)
#define __NR_sched_setattr 314
#define __NR_sched_getattr 315 // x86_64 架构下的系统调用号
// 手动定义 sched_setattr 系统调用
int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags) {
return syscall(__NR_sched_setattr, pid, attr, flags);
}
int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags) {
return syscall(__NR_sched_getattr, pid, attr, size, flags);
}
int main() {
struct sched_attr attr = {
.size = sizeof(attr),
.sched_policy = SCHED_FIFO, // 设置为 SCHED_FIFO
.sched_priority = 50, // 设置优先级
.sched_runtime = 0, // 仅对 SCHED_DEADLINE 有效
.sched_period = 0, // 仅对 SCHED_DEADLINE 有效
.sched_deadline = 0 // 仅对 SCHED_DEADLINE 有效
};
// 调用 sched_setattr 设置调度策略
if (sched_setattr(0, &attr, 0) == -1) {
perror("sched_setattr");
return EXIT_FAILURE;
}
printf("调度策略设置成功,当前策略为 SCHED_FIFO,优先级为 %d\n", attr.sched_priority);
// 等待一段时间,观察调度效果
sleep(10);
//获取一下设置的策略
// 获取当前进程的调度策略
if (sched_getattr(0, &attr, sizeof(attr), 0) == -1) {
perror("sched_getattr");
return -1;
}
printf("当前调度策略: ");
switch (attr.sched_policy) {
case SCHED_FIFO:
printf("SCHED_FIFO\n");
break;
case SCHED_RR:
printf("SCHED_RR\n");
break;
case SCHED_IDLE:
printf("SCHED_IDLE\n");
break;
case SCHED_DEADLINE:
printf("SCHED_DEADLINE\n");
break;
default:
printf("未知调度策略\n");
}
printf("优先级: %d\n", attr.sched_priority);
return EXIT_SUCCESS;
}
示例代码说明
由于我的编译环境有点老glibc 并未直接支持这些较新的系统调用,代码中使用了 syscall
函数来直接调用内核提供的系统调用,编译会报如下错误:
代码逻辑说明
- 设置调度策略:
- 初始化
sched_attr
结构体,设置调度策略为SCHED_FIFO
,优先级为50
。 - 调用
sched_setattr
设置当前进程的调度策略。 - 如果设置失败,打印错误信息并退出。
- 初始化
- 确认调度策略:
- 调用
sched_getattr
获取当前进程的调度策略。 - 根据
sched_policy
的值,打印当前的调度策略和优先级。
- 调用
- 观察调度效果:
- 在设置调度策略后,程序调用
sleep(10)
,等待 10 秒,以便观察调度策略的实际效果。
- 在设置调度策略后,程序调用
示例:设置 SCHED_RR
调度策略
将调度策略改为 SCHED_RR
,并设置优先级为 30:
attr.sched_policy = SCHED_RR;
attr.sched_priority = 30;
示例:设置 SCHED_DEADLINE
调度策略
设置 SCHED_DEADLINE
需要额外的参数:
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = 10000000; // 10ms
attr.sched_period = 100000000; // 100ms
attr.sched_deadline = 100000000; // 100ms
示例:设置 SCHED_OTHER
调度策略
对于非实时调度策略(如 SCHED_OTHER
),不需要设置优先级:
attr.sched_policy = SCHED_OTHER;
attr.sched_priority = 0; // 优先级对 SCHED_OTHER 无效
编译和运行
-
将代码保存为
set_sched.c
。 -
使用以下命令编译:
gcc set_sched.c -o set_sched -lrt
-
以
root
用户运行(因为设置实时调度策略通常需要管理员权限):sudo ./set_sched
注意事项
- 权限问题:设置实时调度策略(
SCHED_FIFO
、SCHED_RR
、SCHED_DEADLINE
)通常需要管理员权限。 - 实时优先级范围:实时调度策略的优先级范围是 1(最低)到 99(最高)。
SCHED_DEADLINE
支持:需要 Linux 内核支持SCHED_DEADLINE
(通常需要较新的内核版本)。
通过以上代码和说明,你可以根据需要动态设置进程的调度策略。