mirror of
https://github.com/gatieme/LDD-LinuxDeviceDrivers.git
synced 2026-08-18 00:58:21 +08:00
description/scheduler: CFS
This commit is contained in:
@@ -139,6 +139,15 @@ Scheduler Microconference Accepted into Linux Plumbers Conference
|
||||
|
||||
Linux 一开始, 普通进程和实时进程都是基于优先级的一个调度器, 实时进程支持 100 个优先级, 普通进程是优先级小于实时进程的一个静态优先级, 所有普通进程创建时都是默认此优先级, 但可通过 **nice()** 接口调整动态优先级(共40个). 实时进程的调度器比较简单, 而普通进程的调度器, 则历经变迁[<sup>5</sup>](#refer-anchor-5):
|
||||
|
||||
在 CFS 算法引入之前, Linux 使用过几种不同的调度算法, 一开始的调度器是复杂度为 O(n) 的始调度算法 (实际上每次会遍历所有任务, 所以复杂度为 O(n)), 这个算法的缺点是当内核中有很多任务时, 调度器本身就会耗费不少时间, 所以, 从 linux 2.5 开始引入赫赫有名的 O(1) 调度器, 然而, linux 是集全球很多程序员的聪明才智而发展起来的超级内核, 没有最好, 只有更好, 在 O(1) 调度器风光了没几天就又被另一个更优秀的调度器取代了, 它就是 CFS 调度器 Completely Fair Scheduler. 这个也是在 2.6 内核中引入的, 具体为 2.6.23, 即从此版本开始, 内核使用 CFS 作为它的默认调度器, O (1) 调度器被抛弃了.
|
||||
|
||||
|
||||
### 1.1.1 O(N) 调度器
|
||||
-------
|
||||
|
||||
O(n) 调度理解起来简单:
|
||||
|
||||
在每次进程切换时, 内核依次扫描就绪队列上的每一个进程, 计算每个进程的优先级, 再选择出优先级最高的进程来运行; 尽管这个算法理解简单, 但是它花费在选择优先级最高进程上的时间却不容忽视. 系统中可运行的进程越多, 花费的时间就越大, 时间复杂度为 O (n).
|
||||
|
||||
|
||||
### 1.1.1 O(1) 调度器:
|
||||
@@ -148,14 +157,15 @@ Linux 一开始, 普通进程和实时进程都是基于优先级的一个调度
|
||||
|
||||
顾名思义, 此调度器为O(1)时间复杂度. 该调度器修正之前的O(n) 时间复杂度调度器, 以解决扩展性问题. 为每一个动态优先级维护队列, 从而能在常数时间内选举下一个进程来执行.
|
||||
|
||||
其基本思想是根据进程的优先级进行调度. 进程有两个优先级, 一个是静态优先级, 一个是动态优先级. 静态优先级是用来计算进程运行的时间片长度的, 动态优先级是在调度器进行调度时用到的, 调度器每次都选取动态优先级最高的进程运行. 由于其数据结构设计上采用了一个优先级数组, 这样在选择最优进程时时间复杂度为 O(1), 所以被称为 O(1) 调度.
|
||||
|
||||
|
||||
|
||||
### 1.1.2 夭折的 RSDL(The Rotating Staircase Deadline Scheduler)调度器
|
||||
-------
|
||||
|
||||
**2007 年 4 月提出, 预期进入 2.6.22, 后夭折.**
|
||||
|
||||
|
||||
|
||||
O(1) 调度器存在一个比较严重的问题: 复杂的交互进程识别启发式算法 - 为了识别交互性的和批处理型的两大类进程, 该启发式算法融入了睡眠时间作为考量的标准, 但对于一些特殊的情况, 经常判断不准, 而且是改完一种情况又发现一种情况.
|
||||
|
||||
|
||||
@@ -173,14 +183,20 @@ Con Kolivas 的完全公平的想法启发了原 O(1) 调度器作者 Ingo Molna
|
||||
> 新的 CFS 调度器的核心同样是**完全公平性**, 即平等地看待所有普通进程, 让它们自身行为彼此区分开来, 从而指导调度器进行下一个执行进程的选举.
|
||||
|
||||
|
||||
具体说来, 此算法基于一个理想模型. 想像你有一台无限个 相同计算力的 CPU, 那么完全公平很容易, 每个 CPU 上跑一个进程即可. 但是, 现实的机器 CPU 个数是有限的, 超过 CPU 个数的进程数不可能完全同时运行. 因此, 算法为每个进程维护一个理想的运行时间, 及实际的运行时间, 这两个时间差值大的, 说明受到了不公平待遇, 更应得到执行.
|
||||
不管是 O(n) 还是 O(1) 调度算法, 其基本思路都是通过一系列运行指标确定进程的优先级, 然后根据进程的优先级确定调度哪个进程, 而 CFS 则转换了一种思路, 它不计算优先级, 而是通过计算进程消耗的 CPU 时间(标准化以后的虚拟 CPU 时间)来确定谁来调度. 从而到达所谓的公平性.
|
||||
|
||||
| 公平性 | 描述 |
|
||||
| 绝对公平性 | CFS 定义了一种新的模型, 其基本思路很简单, 他把 CPU 当做一种资源, 并记录下每一个进程对该资源使用的情况, 在调度时, 调度器总是选择消耗资源最少的进程来运行. 这就是所谓的 "完全公平". 但这种绝对的公平有时也是一种不公平, 因为有些进程的工作比其他进程更重要, 我们希望能按照权重来分配 CPU 资源. |
|
||||
| 相对公平性 | 为了区别不同优先级的进程, 就是会根据各个进程的权重分配运行时间. |
|
||||
|
||||
具体说来, 此算法基于一个理想模型. 想像你有一台无限个 相同计算力的 CPU, 那么完全公平很容易, 每个 CPU 上跑一个进程即可. 但是, 现实的机器 CPU 个数是有限的, 超过 CPU 个数的进程数不可能完全同时运行. 因此, 算法为每个进程维护一个理想的运行时间, 及实际的运行时间, 这两个时间差值大的, 说明受到了不公平待遇, 更应得到执行.
|
||||
|
||||
至于这种算法如何区分交互式进程和批量式进程, 很简单. 交互式的进程大部分时间在睡眠, 因此它的实际运行时间很小, 而理想运行时间是随着时间的前进而增加的, 所以这两个时间的差值会变大. 与之相反, 批量式进程大部分时间在运行, 它的实际运行时间和理想运行时间的差距就较小. 因此, 这两种进程被区分开来.
|
||||
|
||||
|
||||
CFS的算法和实现都相当简单, 众多的测试表明其性能也非常优越. 并得到更多的开发者支持, 所以它最终替代了 RSDL 在 2.6.23 进入内核, 一直使用到现在.
|
||||
|
||||
[Linux的公平调度(CFS)原理 - kummer话你知](https://www.jianshu.com/p/673c9e4817a8)
|
||||
|
||||
### 1.1.4 CK 的 BFS 和 MuQSS
|
||||
-------
|
||||
|
||||
Reference in New Issue
Block a user