之前面试腾讯的时候,被问过这个问题,回答的不是太准确。整理了如下内容,如果有不正确的地方,还请指出来。
Linux 内核实现了如下四种调度类,按优先级从高到低排列:
- 停止类(主要用于多个CPU之间的负载均衡和CPU的热拔插)
- 实时类
- 完全公平调度类
- 空闲类(负责将CPU置于停机状态,直到中断将其唤醒,只有在没有其它任务的时候才能被执行)
和应用层关系密切的两种调度类是实时类和完全公平调度类(CFS),另两种知道其存在就行,一般的后台开发只能接触到这两类。
Linux对实时进程提供了两种调度策略:
- 先进先出(SCHED_FIFO)
FIFO策略是一种简单的策略,即先进先出,它没有时间片的概念,只要没有更高优先级的进程就绪,使用该调度策略的进程就会一直进行。直到发生如下情况:
- 自动放弃CPU,如执行阻塞调用。
- 进程退出。
- 被更高优先级进程抢占。
2. 时间片轮转(SCHED_RR)
在时间片轮转的策略中,具有相同优先级的进程轮流进行,进程每次使用CPU的时间为一个固定长度的时间片。使用该策略的进程一旦被调度器选中,就会一直占用CPU资源,直到发生下面某种情况:
- 时间片耗尽
- 进程自动放弃CPU,如执行阻塞调用。
- 进程退出。
- 被更高优先级进程抢占。
完全公平调度类的调度策略包括(SCHED_OTHER或者SCHED_NORMAL),我们平常开发过程中,使用到的进程就是这种分时进程,CFS底层实现是基于红黑树的,实时进程是基于优先级队列实现。
普通的CFS分时进程,可以通过如下两个系统调用变为实时进程。
sched_getscheduler()和sched_setscheduler(),这两个函数主要调整进程 的优先级以及调度策略。
关于优先级,Linux中为实时进程提供了99个优先级,从内核层面来看,从0到99范围内的优先级属于实时进程的调度范围。从100~139共40个等级属于CFS调度。
此外关于CPU的亲和力。
在对称多处理器(SMP)环境中,一个进程被重新调度时,不一定是在上次执行的CPU上运行。
同一个进程在不同 的CPU之间迁移会带来性能的损失,损失的主要原因在于缓存。在进程迁移到新的处理器上后写入新数据到内存时,原有处理器的缓存就过期了。当进程在不同处理器之间迁移时,会带来两方面的性能损失:
- 进程不能访问老的缓存数据
- 原处理器中缓存中的数据必须标记为无效。
由于迁移会带来性能损失,因此进程调度趋于把进程固定在一个处理器上执行。
有时候需要把进程绑定到某个或某几个CPU上运行,这就需要设置进程的CPU硬亲和力了。Linux提供了非标准的系统调用来获取和修改进程的硬亲和力:即sched_setaffinity()函数和sched_getaffinity()
参考资料:
1. 《Linux环境编程 从应用到内核》高峰。
2. 《深入理解Linux内核》
=============================================================================================
Linux应用程序、内核、驱动、后台开发交流讨论群(745510310),感兴趣的同学可以加群讨论、交流、资料查找等,前进的道路上,你不是一个人奥^_^。