进程调度:
进程调度是属于内核的一部分,他负责当前处理器下一个处理的进程。进程调度可以看成是在可运行进程之间分配有限的处理器时间资源的内核子系统。
(1)进程:分为IO消耗型和CPU 消耗型进程。
当然,对于交互应用,我们当然希望是对IO响应的速度越快越好,但是对于CPU 消耗型进程,我们当然是希望调度器不经常运行他们。所以调度的策略要在两者的矛盾中寻求最大的平衡就是: 既要保证进程响应的速度快,而且还要保证最大系统的利用率。但是Linux 为了保证交互性应用的快速响应,更加倾向于优先调度IO 消耗型进程。
策略:
进程优先级: 通过设定优先级的大小,从而影响系统调用。而且调度程序总是选择时间片没有用尽而且优先级高的进程运行。根据这种思想,就提出了一种动态优先级的调度算法,一开始设定优先级,通过调度算法根据需要+或者-来调整进程的优先级。所以对于IO 消耗型的优先级就不断的被提高,而CPU消耗型的优先级就不段动态的降低。
Linux 提供了两种独立的方式优先级方式nice (-20~+19),并且nice值越小,优先级越高。
第二种是实时,其值是可以配置的,其范围为(0~99)任何实时进程的优先级都高于普通进程。
时间片:CPU分配给各个程序的时间,这个时间的设定是一个比较复杂的过程,试想一下,如果时间片设置的时间比较短,进程间的切换加大,如果时间片太多,交互的响应原则就又欠佳。
综合上面两种方式:
Linux 提供了一种动态调整优先级和时间片的机制:
就是对于交互应用程序在提高优先级的同时,时间片的时间也在增大,根据优先级分配时间片。从而保证了优先级高的进程,执行的时间也长。 进程抢占前所能运行的时间,
但是,不一定进程一次就把时间片的所有时间就用完,他们可以分成好几次,保证他们能尽可能的长时间处于可运行状态。当时间片在消耗尽的时候,没有时间片的进程不会在投入运行,等到所有的进程把时间片都用消耗尽他们的时间片,才重现开始分配时间片。
但是这里面在重新计算进程的时间片是一个非常复杂的过程,他的做法所示维护两个数组,一个是活动数组,一个是过期数组,当一个进程在时间片运行结束后,移植到过期数组之前,时间片已经给她重新分配好了。当活动数组里面没有剩余进程的时候,两个数组交换,把活动数组变成过期数组,过期数组成为活动数组。但是对于交互型强的进程,时间片用完后不是被放入过期数组,而是将他放置到活动数组。这样就可以避免,交互型进程在需要的时候,不能被执行,必须等到数组交换的时候,才能执行。
这两个数组,在内部的组织形式是这样的:
其中array 字段包含两个prio_array_t结构数组,结构体中包含140个双向链表头,一个优先级位图,和一个集合中包含进程数量的计数器。
如何判断一个进程是IO 消耗型还是CPU 消耗型:
Linux 为支持这种推断,在task_struct 的sleep_avg 域 记录了一个进程用于休眠和运行的时间。当一个进程处于休眠状态的时候后,sleep_avg的值不段的增加,在运行的时候,在一个时钟节拍后,就递减。他的范围是(0~MAX_SLEEP_AVG).这种推断不仅会奖励交互型强的进程,而且还会惩罚CPU消耗型进程。
动态优先级= 静态优先级+ 进程交互函数()所计算的来的。
负载平衡程序:
Linux 的调度程序为对称多处理系统的每个处理器准备了单独的可执行队列和锁。
负载平衡器会在当前处理器的可执行队列和系统中的队列进行比较,如果不均衡就会把相对繁忙的队列中的进程抽到当前的可执行队列中。
在负载平衡调用的时候,需要锁住当前处理器的可执行队列并且屏蔽中断。以避免可执行队列被并发的访问。