进程线程(三) --关于进程调度策略,FIFO,RR,CFS

本文探讨了操作系统中的进程调度策略,包括吞吐率与响应时间之间的平衡、不同类型的进程(如IO密集型与CPU密集型)及其调度需求。此外,还介绍了常见的调度算法,如CFS,并解释了如何通过调整nice值和调度策略来优化进程性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该文章参考宋宝华老师的进程视频课程,详细可以去听阅码场宋老师的课程。

CPU/IO消耗型进程

  • 吞吐率 vs. 响应

  • SCHED_FIFO、SCHED_RR

  • SCHED_NORMAL和CFS

  • nice、renice

  • chrt

  • rt_period_us和rt_runtime_us配置

1、 吞吐 和 响应


我们在思考一个系统的调度器时,要理解任何操作系统的调度器设计只追求两个目标:吞吐率大 响应快(低延时) 。但是这两个指标是相对的,吞吐率高必然导致高延迟(响应慢)。

这就像马路上给消防车,救护车让路,消防车救护车的效率高了,但是整个马路的效率低了。

如果不抢占,吞吐会最好,但是响应就很差。

 

吞吐率大:势必要把更多的时间花费在 真实的有用功 上,而不是把时间浪费在频繁的 进程上下文切换 上。

低延时(响应快):要求把优先级高的进程可以随时抢占进来,打断别人,强行插队。但是抢占会引起上下文切换,上下文切换的时间,本身对吞吐率来说,是一个消耗,这个消耗可以降低到 2us 或者更低(这看起来没什么?),但是上下文切换更大的消耗不是切换本身,而是切换会引起大量的cache miss。你明明weibo跑的很爽,现在切过去微信,那么CPU的cache是不太容易命中微信的。

2、 IO消耗型 vs CPU消耗型 进程

 一般来说,IO消耗型的进程 优先级比较高,因为一般和用户体验相关的都是IO消耗型的进程,比如用户敲键盘,或者鼠标,而不是正在编译Android的进程。而CPU消耗型的优先级比较低。

IO消耗型进程:对 CPU的本身的性能不敏感,但是对及时抢占到CPU很敏感。

CPU消耗型进程:对 CPU的本身的性能敏感,对及时抢占到CPU也很敏感。

举个例子,比如要从硬盘上读取4k的数据,

 所以现在有很多ARM的处理器 ,都是 big.little  大核和小核

 原来的都是叫做big.LITTLE,现在的是叫做 DynamIQ big.LITTLE

 

调度算法 

最常用的就是三种,

 在 内核 里面,将优先级分为 0 - 139,数字越小,优先级越高(用户层相反)。

其中 0 - 99 是给RT使用的,

100 - 139 是给 normal 普通进程线程 使用的,

 

 对于普通的进程而言,100 - 139 ,是比较善良的,我们一般不说优先级,一般用 NICE 这个概念来形容,nice值 (-20  19),形容一个人干得好,干的不好。 比如坐地铁,有人经常给老人让座,那么他的nice 值就大,不让座的人 nice 值就小。普通的进程 都是比较善良的,比如 nice 值为 -20的有20块钱,看到有个nice 值为 -16的,就给了他10块钱,nice值 -16的 看到路边有个流浪汉 nice值为-10 ,就给了他4.5块钱......

Documentation/scheduler/sched-nice-design.txt

 

 nice值小的,获得的时间片多,nice值大的获得的 时间片少 (人好,给人让座了)

 动态的奖励和惩罚:比如给你分配了 100ms 的时间片,你每次都用完了,说明你很忙,很喜欢干活,是个CPU消耗型,linux 就会对你进行惩罚,如果你还是喜欢干活,就继续惩罚,nice值越来越低(优先级高)。 反之,给你分配了100ms时间片,你只用了30ms, 说明你可能是一个IO消耗型,喜欢闲着,linux 就会对你奖励,nice 值越来越大(优先级低)。

 对于优先级0-99 只受 RR  FIFO的约束,和 nice 没有关系,只有 普通进程 才受 nice的约束。

 上面就是早期 2.6的调度策略,现在虽然加了很多补丁,算法改了,但是大致原理是相似的。

 

 

 在 1s 内,rt 进程最多只能跑 0.95s , 剩下的 0.05s 让普通人也喝点汤,也能避免RT进程有bug, 把系统挂死了。这个就是 RT进程的熔断机制

 RT进程一般都很少很少,所以给他分配了 0.95s 已经很好了,要是RT进程都很多,还谈什么RT呢?路上都是救护车,警车,那效率一样很低啊。

 注意应用层设置的优先级 0-99  数字越大,优先级越高。这个只针对 FIFO 和 RR策略。

 也可以通过 命令来修改 一些进程的 调度策略 优先级 

 举个例子,CPU两个核,现在跑一个普通的多线程的程序,创建两个线程,默认nice值都是0 ,

主线程, 等待回收线程,不占CPU,其余两个线程,都是while(1) 狂占CPU

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>

void *thread_fun(void *param)
{
	printf("thread pid:%d, tid:%lu\n", getpid(), pthread_self());
	while (1) ;
	return NULL;
}

int main(void)
{
	pthread_t tid1, tid2;
	int ret;

	printf("main pid:%d, tid:%lu\n", getpid(), pthread_self());

	ret = pthread_create(&tid1, NULL, thread_fun, NULL);
	if (ret == -1) {
		perror("cannot create new thread");
		return 1;
	}

	ret = pthread_create(&tid2, NULL, thread_fun, NULL);
	if (ret == -1) {
		perror("cannot create new thread");
		return 1;
	}

	if (pthread_join(tid1, NULL) != 0) {
		perror("call pthread_join function fail");
		return 1;
	}

	if (pthread_join(tid2, NULL) != 0) {
		perror("call pthread_join function fail");
		return 1;
	}

	return 0;
}

 现在跑起来,是一个普通进程,是没有 RT的熔断机制的。

 top 看下,等top稳定之后,看 a.out 的CPU利用率,大概会稳定在 200% 

 不过此时要是,用鼠标拖动窗口,会发现 a.out 的利用率会下降,这说明,有优先级更高的桌面程序抢占到cpu了,所以 a.out 的利用率会下降。要是不拖动窗口,top稳定之后,还是会在200%左右。

 执行下面的命令  将 a.out 设置优先级高一点,-a 是把该进程的所有线程都设置,-p 指优先级,-f 是 fifo 策略,最后跟的是pid 

chrt -f -a -p 50 4507

执行 这条命令后,会将 a.out 设为RT进程了,FIFO策略,是更牛逼了,此时 a.out 的 CPU利用率会降下来,这是为什么?

 为什么会稳定在 160% 呢?

这是因为 设置了 RT进程的熔断机制, 1s  最多跑 0.8s的RT进程,两核的CPU 

 不过此时a.out 变为更牛逼的RT进程之后呢,桌面的用户体验就不太好了,拖动窗口就很慢,因为此时桌面程序的优先级 没有 a.out 高了,抢不过了a.out了。

下面有三个进程,两个RT的进程,一个普通进程,但是他们的CPU占用率如下图 很奇怪,

其实这是由于RT进程的熔断效应造成的,P2 跑不过 P3 只能怪 优先级没有 P1高,和 P3 没有关系。

 现在的内核,普通进程 的调度算法是 CFS 调度算法

 红黑树,是一种二叉树,所有左边的节点,都小于右边的节点。内核 将所有的 普通进程都挂在一颗红黑树上面,挂在上面的不是pid ,也不是 nice值,而是进程的虚拟时间vruntime 。

完全公平调度 :所有的进程追求一个虚拟时间的公平。

虚拟时间怎么计算呢?进程运行一段时间之后,虚拟时间就等于,以前的虚拟时间 + 一个比重,见下图。

delta 是进程运行的物理时间(进程在CPU上跑了1s), NICE_0_LOAD 代表 nice=0的权重,就是 1024 ,se.weight 是进程本身的权重。

所以,对于 nice=0 的进程而言,虚拟时间 就 是 进程运行的物理时间,因为 se.weight = 1024

但是对于那些 nice 比较低的进程,它的权重就会比较大,分母很大,就容易在树的左边,就容易被调度到。要想让 vruntime 长的慢,要么分母大(nice值小的),要么分子小(喜欢睡的进程,IO进程),就容易调度的到。

 

 下面跑一个例子,还是上面的程序 a.out  普通进程。

后台执行两个a.out 由于两个进程都是 普通进程,nice=0 所以公平的划分 CPU ,都是接近 100%的利用率 (两个核)

根据 CFS 完全公平调度算法,要追求所有 红黑树上的 虚拟时间的完全相等,现在将其中一个 a.out 的 nice 值 调整为 -5 ,根据下图的权重可知,nice=-5的权重比 nice=0的权重大了三倍,也就是分母大了三倍,要想保证虚拟时间相等,只有将 nice= -5 的 分子 也增大三倍,也就是给 nice = -5 的进程 3倍的时间,

 

 使用 下面的命令调整, -n 指定 nice 值,-g 所有的线程

renice -n -5 -g 3971

 可以看出来,调整后的CPU占用率是 3:1, 他们加起来还是将近 200% (两核)

 此时,拖到窗口,CPU占用率就会下来,因为桌面程序IO消耗性 一般优先级更高。

注意: CFS 只针对普通进程,和RT进程没关系,RT进程只在 bit 图中寻找第一个bit=1的进程跑(优先级最高的)。

 Linux 当中,绝大多数进程都是 普通进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值