linux内核调度算法(2)--CPU时间片如何分配

Linux性能测试工具之CPU(一) CPUs 1.1 uptime Load averages 的三个值分别代表最近 1/5/15 分钟的平均系统负载。在多核系统中,这些值有可能经常大于1,比如四核系统的 100% 负载为 4,八核系统的 100% 负载为 8。 Loadavg 有它固有的一些缺陷: uninterruptible的进程,无法区分它是在等待 CPU 还是 IO。无法精确评估单个资源的竞争程度; 最短的时间粒度是 1 分钟,以 5 秒间隔采样。很难精细化管理资源竞争毛刺和短期过度使用; 结果以进程数量呈现,还要结合 cpu 阅读详情

转载自:http://blog.youkuaiyun.com/russell_tao/article/details/7103012


内核在微观上,把CPU的运行时间分成许多分,然后安排给各个进程轮流运行,造成宏观上所有的进程仿佛同时在执行。双核CPU,实际上最多只能有两个进程在同时运行,大家在top、vmstat命令里看到的正在运行的进程,并不是真的在占有着CPU哈。

所以,一些设计良好的高性能进程,比如nginx,都是实际上有几颗CPU,就配几个工作进程,道理就在这。比如你的服务器有8颗CPU,那么nginx worker应当只有8个,当你多于8个时,内核可能会放超过多个nginx worker进程到1个runqueue里,会发生什么呢?就是在这颗CPU上,会比较均匀的把时间分配给这几个nginx worker,每个worker进程运行完一个时间片后,内核需要做进程切换,把正在运行的进程上下文保存下来。假设内核分配的时间片是100ms,做进程切换的时间是5ms,那么进程性能下降还是很明显的,跟你配置的worker有关,越多下降得越厉害。

当然,这是跟nginx的设计有关的。nginx是事件驱动的全异步进程,本身设计上就几乎不存在阻塞和中断,nginx的设计者就希望每一个nginx worker可以独占CPU的几乎全部时间片,这点就是nginx worker数量配置的依据所在。


当然,实际的运行进程里,大部分并不是nginx这种希望独占CPU全部时间片的进程,许多进程,比如vi,它在很多时间是在等待用户输入,这时vi在等待IO中断,是不占用时间片的,内核面对多样化的进程,就需要技巧性的分配CPU时间片了。


内核分配时间片是有策略和倾向性的。换句话说,内核是偏心的,它喜欢的是IO消耗型进程,因为这类进程如果不能及时响应,用户就会很不爽,所以它总会下意识的多分配CPU运行时间给这类进程。而CPU消耗进程内核就不太关心了。这有道理吗?太有了,CPU消耗型慢一点用户感知不出来,电信号和生物信号运转速度差距巨大。虽然内核尽量多的分配时间片给IO消耗型进程,但IO消耗进程常常在睡觉,给它的时间片根本用不掉。很合理吧?


那么内核具体是怎么实现这种偏心呢?通过动态调整进程的优先级,以及分配不同长短的CPU时间处来实现。先说内核如何决定时间片的长度。

对每一个进程,有一个整型static_prio表示用户设置的静态优先级,内核里它与nice值是对应的。看看进程描述结构里的static_prio成员。

[cpp]  view plain copy
  1. struct task_struct {  
  2.     int prio, static_prio;  
  3. ......}  

nice值是什么?其实就是优先级针对用户进程的另一种表示法,nice的取值范围是-20到+19,-20优先级最高,+19最低。上篇曾经说过,内核优先级共有140,而用户能够设置的NICE优先级如何与这140个优先级对应起来呢?看代码:

[cpp]  view plain copy
  1. #define MAX_USER_RT_PRIO    100  
  2. #define MAX_RT_PRIO     MAX_USER_RT_PRIO  
  3. #define MAX_PRIO        (MAX_RT_PRIO + 40)  

可以看到,MAX_PRIO就是140,也就是内核定义的最大优先级了。

[cpp]  view plain copy
  1. #define USER_PRIO(p)        ((p)-MAX_RT_PRIO)  
  2. #define MAX_USER_PRIO       (USER_PRIO(MAX_PRIO))  

而MAX_USER_PRIO就是40,意指,普通进程指定的优先级别最多40,就像前面我们讲的那样-20到+19。


[cpp]  view plain copy
  1. #define NICE_TO_PRIO(nice)  (MAX_RT_PRIO + (nice) + 20)  

nice值是-20表示最高,对应着static_prio是多少呢?NICE_TO_PRIO(0)就是120,NICE_TO_PRIO(-20)就是100。


当该进程刚被其父进程fork出来时,是平分其父进程的剩余时间片的。这个时间片执行完后,就会根据它的初始优先级来重新分配时间片,优先级为+19时最低,只分配最小时间片5ms,优先级为0时是100ms,优先级是-20时是最大时间片800ms。我们看看内核是如何计算时间片长度的,大家先看下task_timeslice时间片计算函数:

[cpp]  view plain copy
  1. #define SCALE_PRIO(x, prio) \  
  2.     max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)  
  3.   
  4. static unsigned int task_timeslice(task_t *p)  
  5. {  
  6.     if (p->static_prio < NICE_TO_PRIO(0))  
  7.         return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);  
  8.     else  
  9.         return SCALE_PRIO(DEF_TIMESLICE, p->static_prio);  
  10. }  

这里有一堆宏,我们把宏依次列出看看它们的值:
[cpp]  view plain copy
  1. # define HZ     1000      
  2. #define DEF_TIMESLICE       (100 * HZ / 1000)  

所以,DEF_TIMESLICE是100。假设nice值是-20,那么static_prio就是100,那么SCALE_PRIO(100*4, 100)就等于800,意味着最高优先级-20情形下,可以分到时间片是800ms,如果nice值是+19,则只能分到最小时间片5ms,nice值是默认的0则能分到100ms。


貌似时间片只与nice值有关系。实际上,内核会对初始的nice值有一个-5到+5的动态调整。这个动态调整的依据是什么呢?很简单,如果CPU用得多的进程,就把nice值调高点,等价于优先级调低点。CPU用得少的进程,认为它是交互性为主的进程,则会把nice值调低点,也就是优先级调高点。这样的好处很明显,因为1、一个进程的初始优先值的设定未必是准确的,内核根据该进程的实时表现来调整它的执行情况。2、进程的表现不是始终如一的,比如一开始只是监听80端口,此时进程大部分时间在sleep,时间片用得少,于是nice值动态降低来提高优先级。这时有client接入80端口后,进程开始大量使用CPU,这以后nice值会动态增加来降低优先级。


思想明白了,代码实现上,优先级的动态补偿到底依据什么呢?effective_prio返回动态补偿后的优先级,注释非常详细,大家先看下。

[cpp]  view plain copy
  1. /* 
  2.  * effective_prio - return the priority that is based on the static 
  3.  * priority but is modified by bonuses/penalties. 
  4.  * 
  5.  * We scale the actual sleep average [0 .... MAX_SLEEP_AVG] 
  6.  * into the -5 ... 0 ... +5 bonus/penalty range. 
  7.  * 
  8.  * We use 25% of the full 0...39 priority range so that: 
  9.  * 
  10.  * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs. 
  11.  * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks. 
  12.  * 
  13.  * Both properties are important to certain workloads. 
  14.  */  
  15. static int effective_prio(task_t *p)  
  16. {  
  17.     int bonus, prio;  
  18.   
  19.     if (rt_task(p))  
  20.         return p->prio;  
  21.   
  22.     bonus = CURRENT_BONUS(p) - MAX_BONUS / 2;  
  23.   
  24.     prio = p->static_prio - bonus;  
  25.     if (prio < MAX_RT_PRIO)  
  26.         prio = MAX_RT_PRIO;  
  27.     if (prio > MAX_PRIO-1)  
  28.         prio = MAX_PRIO-1;  
  29.     return prio;  
  30. }  

可以看到bonus会对初始优先级做补偿。怎么计算出这个BONUS的呢?

[cpp]  view plain copy
  1. #define CURRENT_BONUS(p) \  
  2.     (NS_TO_JIFFIES((p)->sleep_avg) * MAX_BONUS / \  
  3.         MAX_SLEEP_AVG)  

可以看到,进程描述符里还有个sleep_avg,动态补偿完全是根据它的值来运作的。sleep_avg就是关键了,它表示进程睡眠和运行的时间,当进程由休眠转到运行时,sleep_avg会加上这次休眠用的时间。在运行时,每运行一个时钟节拍sleep_avg就递减直到0为止。所以,sleep_avg越大,那么就会给到越大的动态优先级补偿,达到MAX_SLEEP_AVG时会有nice值-5的补偿。


内核就是这么偏爱交互型进程,从上面的优先级和时间片分配上都能看出来。实际上,内核还有方法对交互型进程搞优待。上篇说过,runqueue里的active和expired队列,一般的进程时间片用完后进expired队列,而对IO消耗的交互型进程来说,则会直接进入active队列中,保证高灵敏的响应,可见什么叫万千宠爱于一身了。

Linux进程调度机制 Linux进程的调度进制一共有三种方法:时间片轮转调度,优先级调度,完全公平调度。本篇文章就讲解到这里。 阅读详情

相关推荐

GNSS-RTK/INS紧组合里,那个‘杆臂改正’到底怎么算?一个公式讲清INS与天线位置的关系

本文深入解析GNSS-RTK/INS紧组合导航系统中的杆臂改正(Lever Arm Correction)原理与实现方法。详细介绍了杆臂效应的物理本质、数学建模及误差扰动分析,揭示了IMU与GNSS天线位置关系的核心公式,并提供了工程实现中的常见误区与验证方法。通过Python代码示例和紧组合量测模型处理流程,帮助开发者准确理解并应用这一关键技术。

weixin_33137081的博客 357

Linux 学习笔记(七):时间片

Linux 学习笔记(七):时间片

Amentos的博客 5393

线性代数——(期末突击)行列式(上)-行列式计算、行列式的性质

简单解释一下:4213原本的顺序应为1234,对于‘4’而言,‘2’、‘1’、‘3’都应该排在它的前面,所以此处记逆序数为3;对于‘2’而言,‘1’应该排在它的前面,而‘3’排在它之后 是合理的,所以此处只有一个逆序数;最后看‘1’,其后面的‘3’排在后面显然也是合理的,故而4213的逆序数为4.一般我们使用这个性质来计算四阶行列式,也就是将其变换成三角行列式,再计算对角线的值;以主对角线为分界线的就为正三角,反之则为反三角行列式。若行列式某一行(列)为0,则该行列式=0.将和的那一行分开,其余行。

li13437542099的博客 1万+

一文搞懂linux时间片,硬件时钟,软件时钟,实时时钟,时间中断,墙上时间

时间片: ​ 时间片是一个数值,它表明程序在被抢占前所持续运行的时间。 相对时间绝对时间区别: ​ 如果某个时间在5s后呗调度执行,那么系统所需要的不是绝对时间,而是相对时间(比如,相对现在5s后);相反,如果被要求管理当前日期和当前时间,则内核不但要计算流逝的时间而且还要计算绝对时间. 实时时钟(又名硬件时钟,时钟硬件,系统定时器):(理解为一个电子设备) ​ A real-time clock (RTC) is an electronic device (most often in the for

CrazysPopcorn_qian的专栏 7864

【AAAI 2025】轻量级特征增强新范式!FCM 模块助力小目标检测,即插即用提升模型泛化能力

本文介绍了AAAI 2025提出的轻量级特征增强新范式FCM模块,它通过显式分离并双向交互语义与空间特征,有效解决了小目标检测中特征信息失配的核心难题。该模块设计精巧,计算开销极低,能够即插即用式地嵌入YOLO等主流检测网络,显著提升模型对小目标的泛化检测能力,尤其适用于遥感、自动驾驶等对计算资源敏感的实际场景。

weixin_29056145的博客 287

仿真每日一练 | Workbench下薄板疲劳分析

今天给大家介绍Workbench下薄板疲劳分析,采用稳态分析模块进行评估。完成求解后,插入疲劳工具,同时插入对应的寿命进行查看,如图7和图8所示。采用稳态分析模块,导入几何模型,效果如图1。添加固定约束与扭矩,同时添加转速如图4所示。主要包括7要素,对应的类型见图2。求解完成后查看应力,如图6所示。1-1-3、有限元系统模型构建。1-2-1、加载条件/边界条件。1-1-1、几何模型构建。1-1-2、材料定义。1-2-2、求解设置。1-3-1、查看结果。1-3-2、评估结果。1-3-3、修正结果。

ansysxuexizhe的博客 1071

Linux|时间片和上下文切换

这就导致处理器需要更加频繁地切换上下文并执行不同的进程,从而使得被动的上下文切换次数激增(system time 激增),同时也会导致上下文切换占用更大比例的 CPU 时间。在 Linux 中,系统分配给每个进程的时间片的长短并不是固定的,而是受到进程父子关系、进程数量、进程交互性(趋向于 IO 密集型还是处理器密集型)等因素来分配不同的时间片长度。如果时间片的长度过长,那么当 CPU 正在执行的任务较多时,一些简单命令的响应时间也可能会因为 CPU 正在执行其他进程的时间片而延长。

长行 1128

高频网络协议与编程IO相关面试基本问题和知识点整理

网络IO相关基本高频面试基本问题和知识点整合

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 173万+

linux内核调度算法(2)--CPU时间片如何分配 转!

http://blog.youkuaiyun.com/russell_tao/article/details/7103012 内核在微观上,把CPU的运行时间分成许多分,然后安排给各个进程轮流运行,造成宏观上所有的进程仿佛同时在执行。双核CPU,实际上最多只能有两个进程在同时运行,大家在top、vmstat命令里看到的正在运行的进程,并不是真的在占有着CPU哈。 所以,一些设计良好的高性能进程,...

weixin_33724046的博客 139

从零到多智能体:Google Agent开发套件(ADK)入门指南

ADK促进自定义工具生产的能力是其优势之一。本质上,工具只是一个带有描述性文档字符串的Python函数。

独立开发,substack顶级编辑 2491

C#面试题及详细答案120道(61-75)-- 多线程与异步

本文摘要了前后端面试题中关于线程与并发的核心知识点,包括线程与进程的区别(61题)、Thread/ThreadPool/Task的对比(62题)、线程安全实现方法(63题)、lock关键字的原理(64题)、Monitor类的进阶用法(65题)以及死锁的成因与避免(66题)。通过C#代码示例和表格对比,清晰展示了多线程编程的关键概念、应用场景及常见问题解决方案,适合开发者快速掌握面试高频考点。完整内容可访问专栏目录获取更多技术面试题解析。

大剑师兰特的GIS世界 1430

Linux进程调度与O(1)算法深度解析

进程调度是操作系统核心功能,通过优先级机制和时间片轮转实现CPU资源分配。Linux系统采用动态优先级策略,普通进程通过nice值调整优先级,实时进程则享有更高调度权限。O(1)调度算法通过多级优先级队列和活跃/过期队列轮换机制,将调度时间复杂度优化至常数级别,显著提升系统性能。该算法特别适合高并发场景,如数据库服务等需要处理大量进程的服务器环境。理解进程切换的底层实现和调度策略选择,有助于优化系统实时性和吞吐量,解决优先级反转等典型性能问题。

weixin_42627853的博客 315

从零开始跑通3DGS教程:(四)修改(缩放、空间变换)colmap生成的sfm结果

通过colmap进行的sfm的普通方式会丢失场景的物理尺度信息,并且并不在符合一般认知的坐标系下,本文将读取colmap生成的点云和相机pose,将其进行空间变换和缩放之后,重新保存,新保存的结果仍然可以被colmap读取以及进行后续的稠密重建以及3dgs等工作

诺有缸的高飞鸟的博客 1424

进程调度演变过程之O(1)与O(n)调度器 - 进程与线程(十五)

1 调度器概述 任务调度器是操作系统中一个很重要的功能部件,主要功能是把系统中的task调度到各个CPU上去执行,满足如下的性能需求: 调度器必须是公平的:(对于分时的进程,每个任务都应该有机会执行,不能饿死,保证每个进程得到合理的CPU时间) 快速的进程响应时间:(对于交互式进程,需要和用户进行交流,因此对调度延迟比较敏感) 高系统的吞吐量:(对于批处理进程进程,属于那种在后台的默默奉献的,因此它更注重吞吐量的需求) 功耗要小:(对于移动式终端,功耗的需求其实一直以来都没有特别被调度器重视,当然在lin

生活需要深度 1209

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

上一篇: linux内核调度算法(1)--快速找到最高优先级进程
下一篇: linux内核调度算法(3)--多核系统的负载均衡
社区艺术家
博客等级 码龄18年 9粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值