文章转自公众号“人人都是极客”

但凡懂Linux内核的,都知道Linux内核的CFS进程调度算法,无论是从2.6.23将其初引入时的论文,还是各类源码分析,文章,以及Linux内核专门的图书,都给人这样一种感觉,即 CFS调度器是革命性的,它将彻底改变进程调度算法。 预期中,人们期待它会带来令人惊艳的效果。然而这是错觉。人们希望CFS速胜,但是分析来分析去,却只是在某些方面比O(1)调度器稍微好一点点。甚至在某些方面比不上古老的4.4BSD调度器。可是人们却依然对其趋之若鹜,特别是源码分析,汗牛塞屋!为什么CFS对别的调度算法没有带来碾压的效果呢?首先,在真实世界,碾压是不存在的,人与人,事与事既然被放在了同一个重量级梯队比较,其之间的差别没有想象的那么大,根本就不在谁碾压谁。不能被小说电视剧电影蒙蔽了,此外,徐晓冬大摆拳暴打雷雷也不算数,因为他们本就不是一个梯队。

任何领域,革命性的碾压式推陈出新并不是没有,但是概率极低,人们普遍的狂妄在于,总是认为自己所置身的环境正在发生着某种碾压式的变革,但其实,最终大概率不过是一场平庸。

最终就出现了角力,僵持。其次,我们应该看到,CFS调度器声称它会给交互式进程带来福音,在这方面CFS确实比O(1)做得好,但是惊艳的效果来自于粉丝的认同。Linux系统交互进程本来就不多,Linux更多地被装在服务器,而在服务器看来,吞吐是要比交互响应更加重要的。那么以交互为主的Android系统呢?我们知道,Android也是采用了CFS调度器,也有一些是BFS,为什么同样没有带来惊艳的效果呢?我承认,2008年前后出现CFS时还没有Android,等到Android出现时,其采用的Linux内核已经默认了CFS调度器,我们看下Android版本,Linux内核版本以及发行时间的关系:Linux内核在2.6.23就采用了CFS调度器。所以一个原因就是没有比较。Android系统上,CFS没有机会和O(1)做比较。另外,即便回移一个O(1)调度器到Android系统去和CFS做AB,在我看来,CFS同样不会惊艳,原因很简单,Android系统几乎都是交互进程,前台进程却永远只有一个,你几乎感受不到进程的切换卡顿,换句话说,即便CFS对待交互式进程比O(1)好太多,你也感受不到,因为对于手机,平板而言,你切换APP的时间远远大于进程切换的时间粒度。那么,CFS到底好在哪里?简单点说,CFS的意义在于, 在一个混杂着大量计算型进程和IO交互进程的系统中,CFS调度器对待IO交互进程要比O(1)调度器更加友善和公平。理解这一点至关重要。其实,CFS调度器的理念非常古老,就说在业界,CFS的思想早就被应用在了磁盘IO调度,数据包调度等领域,甚至最最古老的SRV3以及4.3BSD UNIX系统的进程调度中早就有了CFS的身影,可以说,Linux只是使用CFS调度器,而不是设计了CFS调度器!就以4.3BSD调度器为例,我们看一下其调度原理。4.3BSD采用了1秒抢占制,每间隔1秒,会对整个系统进程进行优先级排序,然后找到优先级最高的投入运行,非常简单的一个思想,现在看看它是如何计算优先级的。首先,每一个进程j均拥有一个CPU滴答的度量值Cj,每一个时钟滴答,当前在运行的进程的CPU度量值C会递增:

当一个1秒的时间区间i过去之后,Cj被重置,该进程j的优先级采用下面的公式计算:

可以计算,在一个足够长的时间段内,两个进程运行的总时间比例,将和它们的Base_PrioBase_Prio优先级的比例相等。4.3BSD的优先级公平调度是CPU滴答驱动的。现在看Linux的CFS,CFS采用随时抢占制。每一个进程j均携带一个 虚拟时钟VCj,每一个时钟滴答,当前进程k的VCk会重新计算,同时调度器选择VC最小的进程运行,计算方法非常简单:可见, Linux的CFS简直就是4.3BSD进程调度的自驱无级变速版本!如果你想了解CFS的精髓,上面的就是了。换成语言描述,CFS的精髓就是 “n个进程的系统,任意长的时间周期T,每一个进程运行T/n的时间!”当然,在现实和实现中,会有80%的代码处理20%的剩余问题,比如如何奖励睡眠太久的进程等等,但是这些都不是精髓。综上,我们总结了:

  • 现实世界很难碾压同级别的人或事。

  • 大量的Linux服务器不需要照顾交互进程,CFS优势无法凸显。

  • 大量的Android系统没有和O(1)同台竞技的机会。

  • 大量的Android系统交互进程很难感知进程调度这件事。

  • CFS调度思想古已有之。

所以无论从概念还是从效果,Linux CFS调度器均没有带来令人眼前一亮的哇塞效果。但是还缺点什么。嗯,技术上的解释。分析和解释任何一个机制之前,必然要先问,这个机制的目标是什么,它要解决什么问题,这样才有意义。而不能仅仅是明白了它是怎么工作的。那么Linux CFS调度器被采用,它的目标是解决什么问题的呢?它肯定是针对O(1)算法的一个问题而被引入并取代O(1),该问题也许并非什么臭名昭著,但是确实是一枚钉子,必须拔除。O(1)调度器的本质问题在于 进程的优先级和进程可运行的时间片进行了强映射!

也就是说,给定一个进程优先级,就会计算出一个时间片与之对应,我们忽略奖惩相关的动态优先级,看一下原始O(1)算法中一个进程时间片的计算:

#define BASE_TIMESLICE(p) (MIN_TIMESLICE + /
((MAX_TIMESLICE - MIN_TIMESLICE) * /
(MAX_PRIO-1 - (p)->static_prio) / (MAX_USER_PRIO-1)))static inline unsigned int task_timeslice(task_t *p){return BASE_TIMESLICE(p);
}

直观点显示:

针对上述问题,2.6内核的O(1)引入了双斜率来解决:

static unsigned int task_timeslice(task_t *p){if (p->static_prio 0))return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);elsereturn SCALE_PRIO(DEF_TIMESLICE, p->static_prio);
}

直观图示如下:

貌似问题解决了,但是如果单单揪住上图的某一个优先级子区间来看,还是会有问题,这就是相对优先级的问题。我们看到,高优先级的时间片是缓慢增减的,而低优先级的时间片却是陡然增减,同样都是相差同样优先级的进程,其优先级分布影响了它们的时间片分配。本来是治瘸子,结果腿好了,但是胳臂坏了。本质上来讲,这都源自于下面两个原因:固定的优先级映射到固定的时间片。相对优先级和绝对优先级混杂。那么这个问题如何解决?优先级和时间片本来就是两个概念,二者中间还得有个变量沟通才可以。优先级高只是说明该进程能运行的久一些,但是到底久多少,并不是仅仅优先级就能决定的,还要综合考虑,换句话距离来说,如果只有一个进程,那么即便它优先级再低,它也可以永久运行,如果系统中有很多的进程,即便再高优先级的进程也要让出一些时间给其它进程。所以,考虑到系统中总体的进程情况,将优先级转换为权重,将时间片转换为份额,CFS就是了。最终的坐标系应该是权重占比/时间片坐标系而不是权重(或者优先级)/时间片。应该是这个平滑的样子:

看来,Linux CFS只是为了解决O(1)中一个“静态优先级/时间片映射”问题的,那么可想而知,它又能带来什么惊艳效果呢?这里还有个“但是”,这个O(1)调度器的问题其实在计算密集型的守护进程看来,并不是问题,反而是好事,毕竟高优先级进程可以无条件持续运行很久而不切换。这对于吞吐率的提高,cache利用都是有好处的。无非也就侵扰了交互进程呗,又有何妨。当然,使用调优CFS的时候,难免也要遇到IO睡眠奖惩等剩余的事情去设计一些trick算法,这破费精力。对了,还要设置你的内核为HZ1000哦,这样更能体现CFS的平滑性,就像它宣称的那样。我难以想象,除了Ubuntu,Suse等花哨的桌面发行版之外,还有哪个Linux需要打开HZ1000,服务器用HZ250不挺好吗?关于调度的话题基本就说完了,但是在进入下一步固有的喷子环节之前,还有两点要强调:

  1. CFS的时间片是动态的,是系统负载均衡以及其优先级的函数,这便可以把进程调度动态适应到系统最佳,以节省切换开销。

  2. 即便是到了多核时代,对于实时进程依然像单核时代那般严格遵循最优先调度。

我还是想说,在调度器设计方面,大部分的人们关注点错了!

在CPU核数越来越多的时代,人们更应该关心把进程调度到哪里CPU核上而不是某个CPU核要运行哪个进程

单核时代一路走过来的Linux,发展迅猛,这无可厚非,但是成就一个操作系统内核的并不单单是技术,还有别的。这些当然程序员们很不爱听,程序员最烦非技术方面的东西了,程序员跟谁都比写代码,程序员特别喜欢喷领导不会写代码云云。Linux在纯技术方面并不优秀,Linux总体上优秀的原因是因为有一群非代码不明志的程序员在让它变得越来越优秀,另一方面还要归功于开源和社区。Linux的学习门槛极低,如果一个公司能不费吹灰之力招聘到一个Linux程序员的话,那它干嘛还要费劲九牛二虎之力去招聘什么高端的BSD程序员呢?最终的结果就是,Linux用的人极多,想换也换不掉了。但无论如何也没法弥补Linux内核上的一些原则性错误。Linux内核还是以原始的主线为base,以讲Linux内核的书为例,经典的Robert Love的《Linux内核设计与实现》,以及《深入理解Linux内核》,在讲进程调度的时候,关于多核负载均衡的笔墨都是少之又少甚至没有,如此经典的著作把很多同行引向了那万劫不复的代码深渊。于是乎,铺天盖地的CFS源码分析纷至沓来。但其实,抛开这么一个再普通不过的Linux内核,现代操作系统进入了多核时代,其核心正是在cache利用上的革新,带来的转变就是进程调度和内存管理的革新。review一下Linux内核源码,这些改变早就已经表现了出来。可悲的是,关于Linux内核的经典书籍却再也没有更新,所有的从传统学校出来的喜欢看书学习的,依然是抱着10年前的大部头在啃。当然了,Linux内核作为一个代码来讲,它是普适的,所以社区很难看到且关注单单是多核的问题,社区关注的最多的是可维护性,而不是性能。Linux新特性在128MB内存的i386机器上跑没有问题,那就是OK的。只要不是80%以上的人遭遇的新问题,社区是从不care的,同时,正因为如此,社区还会引入bug,这也是令人想叹息都不能叹息。我的看法吧,社区只是一个一切以代码为准绳的程序员社区,社区不会过于关注体系结构的发展和新特性,这些都是厂商的事情。回到进程调度的话题,正因为Linux一直在关注调度算法本身以及其实现的代码,才会出现The Linux Scheduler: a Decade of Wasted Cores,这篇十分中肯的paper:http://www.ece.ubc.ca/~sasha/papers/eurosys16-final29.pdf同样,我一向喷的TCP也是如此,人们关注TCP的实现代码本身,才会让它越来越复杂,然后越来越脆弱,也许你会说这就是进化,但是趁着万劫不复前,不是还有回炉的机会吗?还没有进化到必须继续进化的地步吧。如果站在外面看且具有强制措施,估计早就没有垃圾TCP了吧。浙江温州皮鞋湿,下雨进水不会胖。

用c语言实现对n个进程采用“短进程优先”算法的进程调度_为什么Linux CFS调度器没有带来惊艳的碾压效果?...相关推荐

  1. 短作业优先算法c语言实现,OS短作业优先调度算法C语言

    OS短作业优先调度算法C语言 采用短作业优先调度算法调度程序 学 号: 姓 名: 专 业: 指导老师: 日 期: 目录 一.实验题目3 二.课程设计的目的3 三.设计内容3 四.设计要求3 五.主要数 ...

  2. 【Linux 内核】CFS 调度器 ② ( CFS 调度器 “ 权重 “ 概念 | CFS 调度器调度实例 | 计算进程 “ 实际运行时间 “ )

    文章目录 一.CFS 调度器 " 权重 " 概念 二.CFS 调度器调度实例 ( 计算进程 " 实际运行时间 " ) 一.CFS 调度器 " 权重 & ...

  3. 非抢占式优先算法例题_非抢占短作业优先算法源代码(C语言)

    #include #include #define MAX 5 //进程数 /*短作业优先算法*/ struct pro { int num; //进程名 int arriveTime; //到达时间 ...

  4. Linux CFS调度器之负荷权重load_weight--Linux进程的管理与调度(二十五)

    日期 内核版本 架构 作者 GitHub CSDN 2016-07-29 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度 ...

  5. VB.net:VB.net编程语言学习之基于VS软件利用VB.net语言实现对SolidWorks进行二次开发的简介、案例应用之详细攻略

    VB.net:VB.net编程语言学习之基于VS软件利用VB.net语言实现对SolidWorks进行二次开发的简介.案例应用之详细攻略 目录 调用SolidWorks功能简介 1.宏录制步骤 (1) ...

  6. 【Linux 内核】CFS 调度器 ③ ( 计算进程 “ 虚拟运行时间 “ )

    文章目录 一.计算进程 " 虚拟运行时间 " 一.计算进程 " 虚拟运行时间 " 在上一篇博客 [Linux 内核]CFS 调度器 ② ( CFS 调度器 &q ...

  7. 进程管理(二十二)—CFS调度器

    CFS是内核使用的一种调度器或调度类,它主要负责处理三种调度策略:SCHED_NORMAL.SCHED_BATCH和SCHED_IDLE.调度器的核心在挑选下一个运行的进程时有可能会遍历所有的调度类别 ...

  8. 进程调度算法-短作业优先调度算法(SJF)

    基本思想 SJF算法是以作业的长度来计算优先级,作业越短,其优先级越高.作业的长短是作业所要求的运行时间来衡量的. 算法性能评价 面向用户 周转时间 从作业被提交给系统开始,到作业完成为止的这段时间间 ...

  9. c语言bmp图片合并,C语言实现对bmp格式图片打码

    相信大家看到上面的标题一定觉的是上面高大上的技术,其实很简单. 前提准备:一张bmp格式的图片,如果没有的话,可以用Windows的画图软件来才裁剪.设置像素大小为(1024,768): 程序原理:将 ...

最新文章

  1. VC++技术内幕(三)
  2. mysql插入数据显示中文乱码
  3. python3 multiprocessing 多进程 列表类型 listproxy 清除内容
  4. C语言assert的用法
  5. 自动发送邮件(整理版)
  6. 大牛书单 | 搜索大牛都读什么书?
  7. python Tags 母板 组件 静态文件相关 自定义simpletag inclusion_tag
  8. MySQL中授权(grant)和撤销授权(revoke)
  9. win10计算机权限不足是,深度技术windows10系统电脑权限不足导致无法格式化分区的方法...
  10. 太阳天顶角和方位角计算
  11. 完整的连接器设计手册_广西直销施耐德漏电断路器选型手册
  12. HTML5游戏开发进阶指南.pdf
  13. 计算机仿真类的论文,最新计算机仿真参考文献 计算机仿真专著类参考文献有哪些...
  14. Android中action启动方法大全
  15. c语言口语评分系统,FCE口语评分标准:考官更喜欢这样的考生
  16. 2021年焊工(初级)新版试题及焊工(初级)复审模拟考试
  17. AutoCAD参照编辑期间不允许使用 SAVE 命令怎么办
  18. Java 工厂设计模式
  19. 光纤收发器的6个指示灯说明
  20. java基于springboot家庭水电燃气网上交费系统

热门文章

  1. [codevs 1922] 骑士共存问题
  2. CVPR 2021 《Domain-robust VQA with diverse datasets and methods but no target labels》论文笔记
  3. 混合牛奶pascal程序
  4. 51单片机的配p10端口c语言,stc12c5a16s2的单片机的p5口做普通端口怎么定义?
  5. 2019小程序没必要做了_2019微信小程序的发展前景怎么样?有必要开发微信小程序吗?...
  6. mos 多路模拟电子开关_【原创】单火线智能开关技术介绍及分析
  7. android百分比布局适配,安卓屏幕适配-百分比布局
  8. flask 上下文管理
  9. webpack 引入模块import 后面加入{}和不加大括号有什么区别
  10. 计算机网络(10)-----TCP的拥塞控制