您的位置:首页 > 运维架构 > Linux

linux 进程基础(四)

2015-06-13 23:52 375 查看
本小结主要对linux进程的调度部分进行学习总结。
linux是个支持多任务的操作系统,因此才会涉及到进程的调度,调度的目的是为了让多个进程并
存、在当前CPU是多核(单核的CPU系统中面对多任务时也涉及到进程的调度)的情况下,CPU可以高效的
对处于可执行状态的进行调度处理、以提高系统的业务处理能力。
进程的调度其实质就是CPU对处于可执行状态的进程进行处理的过程,这要求linux进程调度器在设
计上可以处理几个甚至是相互矛盾的目标:

A、高效性:高效意味着在相同的时间下要完成更多的任务; B、实时性: 在系统相当的负载下,也要保证系统的响应时间; C、公平性:所有需要调度的进程都有机会被调度执行; D、软实时调度:系统必须有效的调用实时进程,但不保证一定满足其要求; 即便是多核技术如何发展,与任务相比总是处在粥少僧多的局面,再说核多了,价位也高了,因此在对支持多任务的操作系统而言,硬件上的够用、适用,系统级的资源利用率高效才是关键。 调度往往是一个复杂的过程,这个过程可以用火车站对进程、出站的火车进行管理的场景来类比,我们来看一些熟悉的场景:场景一:“如果是一量普快的火车和高铁同时需要发车(在同一条铁路上跑),结果高铁优先上路”。 这个场景高铁和普快都是要发车的,即我们进程调度时处于可执行状态的进程、并很显然高铁的优先级比普快的火车高,这一需要共用的铁路就是我们进程调度中的CPU; 现在问题来了,高铁凭什么优先就能优先发车呢?其答案是他的优先级比普快的高? 针对这个答案,我们继续发问,高铁的优先级凭啥就可以比普快的高?结合实际我们发现高铁像用户收取更高的服务费用,那么乘坐高铁的人理所当然要能享受更好的服务,更好的座位、乘车环境、更短的乘车时间,这个就是答案,现在我们对这个答案更进一步抽象,我们发现是用户的需求触发铁道部门将高铁的优先级定为比普快列车的高。
从这个场景我们可看出,在谁可以优先发车的问题上,一个很重要的关键因素取决于列车的优先级。在系统的进程调度中,这个优先级同样存在,进程的优先级为存在用户自行决定和系统界定两种方式(内核动态调整)。 场景中的铁道部很像系统调度中的调度器,根据业务的需求,他们本身也会对将在铁道上奔跑的列车分为实时性列车、和实时性列车,我们可以这样理解所谓的实时性列车就是军列,非实时性的列车就是我们上面的高铁和普快,军列一般很少出动、一旦出动都是大事,因此,在有军列出发的情况下,铁道部提供的服务必须是实时性的,即哪怕你铁道部事情再多,也是必须提供可控的轨道交通资源来完成过的任务,甚至这条铁道成为专用。这类应用在系统实现中被称为硬实时,而现在的linux系统作为通用的操作系统,都没做到这一点,他们的业务处理模式是场景一种的高铁、普快这类型的列车,这种模式在linux中被称为“软实时”,即尽可能的满足进程的运行需求。
显然军列并不是时刻存在、然而一旦存在了铁道部门就得处理,这个动态处理的过程可类比与操作系统中内核的动态调整。这里需要注意的是“军列”的高优先级是由用户自己(应用程序)自己决定的作为操作系统部分的铁道部门只可执行,不能臆断臆断军列的优先级(自己本身可做主的部分例外)。军列这种实时性的列车调度很简单,有了需求就发车; 我们发现上述处理过程是,优先级高的高铁优先发车后,才是次优先级的普快列车发车,由于优先级的判定,很可能导致一个非常不公平的现象发生,假设高铁有100节,整个高铁完全驶离车站需要2小时,而普快只有2节,驶离车站只需要2分钟,但由于高铁优先级高,普快只有等待2小时后再发车。实际linux操作系统实现中,这类型的情况也是有所考虑和措施的,我们后续再说。我们先来说这个问题,细心的读者可能会发现,我们这个场景中,高铁和普快的级别并不对等,如果车站需要同时发车都是高铁或者都是普快那怎么办?我们来看下面场景二。场景 二:火车站现在需要同时发车的是三量高铁(或三量普快);
场景二类比进程调度中普通进程的调度。 假设火车站发车的这三量列车的代号分别为A、B、C,火车站只有一条铁道供列车使用;
现在火车要有发3个车的需求,如果它采用的策略是:那个列车准备工作优先完成,就优先将那个列车发出去,即先来先服务的方式,那么也是能处理三个级别一样的列车都有发车需求的情况。现假设A列车优先完成准备工作,火车站也将这列车发出去了,但很不幸的是列车A有100节,发车时间也需要2小时,那么作为级别相等的列车B、C自然是忍无可忍的,我们级别都一样凭什么我要等你那么九久,你火车站难道就没有更公平的玩法了吗? 火车站当然还有其他的玩法,这就是我们要将的基于时间片的列车调度方式了,该场景中现假设调度过程如下(每次调度列车时只给其一分钟时间,每调度一次可让10节长的列车驶离车站):
第一轮次调度:
列车A:给你一分钟发车,结果是列车A还有90节在火车站中,记录A的发车10节、已发过一次车; 列车B:给你一份钟发车,结果是列车B还有10节在火车站中,记录B的发车10节、已发过一次车; 列车C:给你一份钟发车,结果是列车C已能完全驶离车站; 第二轮次调度: 列车A:给你一分钟发车,结果是列车A还有80节在火车站中,A发车20节、已发过二次车; 列车B:给你一份钟发车,结果是列车B还有10节在火车站中,B发车20节、已发过二次车; 第三轮次调度: 列车A:给你一分钟发车,结果是列车A还有70节在火车站中,A发车30节、已发过二次车;
……
上述过程一直循环,最后A、B、C三量列车都全部驶离火车站。
这种调度方式,在操作系统中称为基于时间片的调度方式,这种方式为相同级别的列车调度提供了
较高的公平性。这里需要强调的是,这种调度的模式仅适用于级别相同的列车。 ……
实际上linux系统在调度这种普通进程时,复杂度会比这个更高。
实时进程调度的中心思想是,让处于可执行状态的最高优先级的实时进程尽可能地占有CPU,因为它有实时需求;而普通进程则被认为是没有实时需求的进程,于是调度程序力图让各个处于可执行状态的普通进程和平共处地分享CPU,从而让用户觉得这些进程是同时运行的。与实时进程相比,普通进程的调度要复杂得多。内核需要考虑两件麻烦事:一、动态调整进程的优先级按进程的行为特征,可以将进程分为“交互式进程”和“批处理进程”:交互式进程(如桌面程序、服务器、等)主要的任务是与外界交互。这样的进程应该具有较高的优先级,它们总是睡眠等待外界的输入。而在输入到来,内核将其唤醒时,它们又应该很快被调度执行,以做出响应。比如一个桌面程序,如果鼠标点击后半秒种还没反应,用户就会感觉系统“卡”了;批处理进程(如编译程序)主要的任务是做持续的运算,因而它们会持续处于可执行状态。这样的进程一般不需要高优先级,比如编译程序多运行了几秒种,用户多半不会太在意;如果用户能够明确知道进程应该有怎样的优先级,可以通过nice、setpriority系统调用来对优先级进行设置。(如果要提高进程的优先级,要求用户进程具有CAP_SYS_NICE能力。)然而应用程序未必就像桌面程序、编译程序这样典型。程序的行为可能五花八门,可能一会儿像交互式进程,一会儿又像批处理进程。以致于用户难以给它设置一个合适的优先级。再者,即使用户明确知道一个进程是交互式还是批处理,也多半碍于权限或因为偷懒而不去设置进程的优先级。(你又是否为某个程序设置过优先级呢?)于是,最终,区分交互式进程和批处理进程的重任就落到了内核的调度程序上调度程序关注进程近一段时间内的表现(主要是检查其睡眠时间和运行时间),根据一些经验性的公式,判断它现在是交互式的还是批处理的?程度如何?最后决定给它的优先级做一定的调整。进程的优先级被动态调整后,就出现了两个优先级:1、用户程序设置的优先级(如果未设置,则使用默认值),称为静态优先级。这是进程优先级的基准,在进程执行的过程中往往是不改变的;2、优先级动态调整后,实际生效的优先级。这个值是可能时时刻刻都在变化的;二、调度的公平性在场景二中即便都是号称优先级相同的列车,实际调度的结果还是可能存在不公平的情况,为了避免谁运气好谁就占得多这样不可控的情况发生。linux实现公平调度基本上是两种思路:1、给处于可执行状态的进程分配时间片(按照优先级),用完时间片的进程被放到“过期队列”中。等可执行状态的进程都过期了,再重新分配时间片;2、动态调整进程的优先级。随着进程在CPU上运行,其优先级被不断调低,以便其他优先级较低的进程得到运行机会;后一种方式有更小的调度粒度,并且将“公平性”与“动态调整优先级”两件事情合而为一,大大简化了内核调度程序的代码。因此,这种方式也成为内核调度程序的新宠。强调一下,以上两点都是仅针对普通进程的。而对于实时进程,内核既不能自作多情地去动态调整优先级,也没有什么公平性可言。普通进程具体的调度算法非常复杂,并且随linux内核版本的演变也在不断更替(不仅仅是简单的调整),所以本文就不继续深入了。场景三:普快已经在铁轨上跑了,这时候来了一量高铁……这种场景我们看到的结果是,普快停下来了让高铁超车先走,自己再走。 这种场景叫做抢占,在操作系统中同样存在,linux操作系统在处理这种情况时时这样的:
未完待续……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息