进程的调度是进程部分的核心-很显然,若是没有调度,咱们也不须要进程了!咱们在上一篇文章的第二部分实现了一个最简单的按照时间片的调度算法,每一个进程都平均执行100毫秒。java
while (true){ processing = nextProcessing(); processing.run(); wait(100); //每100毫秒分片 processing.interrupt(); }
那么Linux中如何实现的呢?咱们先来看流程。调度相关的代码都在sched.c
中。这个就是Linux代码核心中的核心,它被运行在亿万台机器上,每台机器每一个时钟周期就要执行一次,看到它是否是有点激动?终于知道“高性能的底层代码”长什么样了!linux
这个文件的核心函数是asmlinkage void __sched schedule(void)
,这就是调度部分的具体代码。当我读完并注释以后才发现已经有不少注释版本了,好比这篇文章:http://blog.csdn.net/zhoudaxia/article/details/7375836,因此就不贴代码了。我注释后的代码在sched.c(4079行开始)里。不过不读源码,不用那些关键词去搜索,估计也找不到一些好文章,这也是一个学习的过程吧。git
这个方法有两个重要的点,一个是pick_next_task(rq);
,获取下一个可执行进程,它涉及到调度算法;一个是context_switch(rq, prev, next);
,这就是所谓的“上下文切换”了。github
咱们前面的“100毫秒算法”算法固然是很是粗糙的。在了解货真价实的Linux调度算法时,不妨看看,调度系统须要考虑什么问题(非官方不权威总结):算法
咱们的“100毫秒算法”不知足1和3,对于2来讲其实也不太好(可能有些进程都不会执行那么久)。若是咱们把时间缩短,换成1毫秒怎么样呢?咱们知道,“进程切换”自己也有开销,这样子频繁切换,岂不是得不偿失了?函数
实际上,由于其核心地位,Linux的调度算法一旦提高一点点性能,对整个工业界的提高也是巨大的。对于算法高手来讲,这里成了大显身手的好地方。因此Linux调度算法的变化那是至关的快,从O(n)调度器到O(1)调度器,再到2.6.23中的"CFS(completely fair schedule)",让人看得都晕了!性能
了解了要解决的问题,或许会更容易理解一点。O(n)和O(1)算法都是基于时间片的,基本思路就是:给进程指定优先级,IO高、交互强的进程给予更高的优先级,CPU占用高的则下降优先级,每次选优先级最高的执行;同时为每一个进程分配时间片(每一个进程的时间片都是动态调整的),每一个进程每次执行的时间就是这个时间片的时间。O(n)和O(1)的区别在于从优先级队列里取进程的时候的时间复杂度而已。具体细节就很少说了。学习
而"CFS"则是使用了一个"vruntime"的概念来保存执行时间。同时它用一颗红黑树来对进程作排序,vruntime越小的进程会被越先执行,因此它的时间复杂度是O(logn)。它的代码在kernel/sched_fair.c
中。.net
另外还有个“实时调度算法”的概念。这些就是“加塞的”的进程,它们优先于CFS的全部进程。对应的类型是SCHED_FIFO
和SCHED_RR
,在sched.h
中能够看到。设计
调度部分就这么多,还有些细节,例如CFG具体实现,书里已经很详细了,就不重复记录,省得写晕了!