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

Linux内核之内核进程调度

2017-02-18 09:21 483 查看
  Linux进程调度是通过内核子系统:进程调度程序完成的。进程调度程序决定投入运行的进程、何时运行已经运行时长。从这里可以看出,进程调度程序就是一个在可运行进程之间分配有限的处理器时间资源的内核子系统

一、基本概念

1.1 多任务

多任务系统分类

  非抢占式多任务和抢占式多任务。Linux系统提供了抢占式的多任务模式。

抢占

  抢占式多任务环境下,调度程序决定什么时候停止一个进程的运行(将正在运行的进程挂起),以便其他进程能够有机会占有CPU。这个将进程挂起的动作就叫做抢占。

时间片

  进程能够处于运行态时间即进程占有CPU的时间称之为时间片。这个值是在进程投入运行前就预设好的。

让步

  非抢占式多任务环境下,除非进程自己主动停止运行,否则进程就会一直占有CPU。进程主动挂起的动作就叫做让步.

1.2 Linux进程调度基础

  Linux进程调度采用了完全公平调度算法,简称CFS。但是要注意的是,进程也分为普通和实时的,系统中大多数进程都是普通进程,而CFS是一个普通进程的调度类。至于实时进程,则采用了另外的调度算法:先入先出(不使用时间分片)、

1.2.1 调度策略

  调度策略决定了调度程序在何时让什么进程运行。进程可以分为CPU密集型和I/O密集型两种。I/O密集型的进程大部分时间都在用来提交I/O请求和等待I/O请求。CPU密集型进程大部分时间都花在执行代码上。对于CPU密集型的进程,调度策略往往是尽可能的降低调度频率,延长进程占有CPU的时间。也就是说,CPU密集型进程希望占有CPU的时间越长越好,而I/O密集型进程则不需要长时间占有CPU,这里就是一个调度策略所需要处理的矛盾。即,调度策略主要在两个矛盾之间寻找平衡:进程响应时间短和最大的系统利用率。Linux进程调度策略更倾向于有限调度I/O密集型的进程。

1.2.2 进程优先级

  Linux采用了两种不同的进程优先级。

- 第一种:nice值

  nice值得优先级范围是从-20到+19,nice值越大,优先级越小。Linux系统的nice值代表的是时间片的比例,因此越小的nice值,占有CPU的时间也就会越长,其默认值为0。通过命令 ps -el 可以报告系统中的进程表,NI列代表的就是nice值。如下:

[root@master ~]# ps -el
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0      1      0  0  80   0 -  4839 poll_s ?        00:00:03 init
1 S     0      2      0  0  80   0 -     0 kthrea ?        00:00:00 kthreadd
1 S     0      3      2  0 -40   - -     0 migrat ?        00:00:01 migration/0
1 S     0      4      2  0  80   0 -     0 ksofti ?        00:00:00 ksoftirqd/0
1 S     0      5      2  0 -40   - -     0 cpu_st ?        00:00:00 migration/0
5 S     0      6      2  0 -40   - -     0 watchd ?        00:00:00 watchdog/0
1 S     0      7      2  0 -40   - -     0 migrat ?        00:00:01 migration/1
1 S     0      8      2  0 -40   - -     0 cpu_st ?        00:00:00 migration/1
1 S     0      9      2  0  80   0 -     0 ksofti ?        00:00:00 ksoftirqd/1
5 S     0     10      2  0 -40   - -     0 watchd ?        00:00:00 watchdog/1
1 S     0     11      2  0  80   0 -     0 worker ?        00:00:49 events/0
1 S     0     12      2  0  80   0 -     0 worker ?        00:00:11 events/1
1 S     0     13      2  0  80   0 -     0 worker ?        00:00:00 cgroup
1 S     0     14      2  0  80   0 -     0 worker ?        00:00:00 khelper
1 S     0     15      2  0  80   0 -     0 worker ?        00:00:00 netns
1 S     0     16      2  0  80   0 -     0 async_ ?        00:00:00 async/mgr
1 S     0     17      2  0  80   0 -     0 worker ?        00:00:00 pm
1 S     0     18      2  0  80   0 -     0 bdi_sy ?        00:00:00 sync_supers
1 S     0     19      2  0  80   0 -     0 bdi_fo ?        00:00:00 bdi-default
1 S     0     20      2  0  80   0 -     0 worker ?        00:00:00 kintegrityd/0
1 S     0     21      2  0  80   0 -     0 worker ?        00:00:00 kintegrityd/1
......


注意上述的进程优先级下面有 - 这个符号,该符号的含义是指:该进程不是实时进程

Linux中可以通过renice命令调整进程的优先级。

第二种:实时优先级与时间片

  优先级变化范围:0到99。值越大,优先级越高。任何实时进程的优先级都高于普通进程。实时优先级和nice优先级处于两个不想交的范畴。Linux下查看实时优先级命令: ps -eo state,uid,pid,rtprio

[root@master ~]# ps -eo state,uid,pid,rtprio
S   UID    PID RTPRIO
S     0      1      -
S     0      2      -
S     0      3     99
S     0      4      -
S     0      5     99
S     0      6     99
S     0      7     99
S     0      8     99
S     0      9      -
S     0     10     99
S     0     11      -
S     0     12      -
......


实时优先级位于RTPRIO列下面。 上述的进程优先级下面有 - 这个符号,该符号的含义是指:该进程不是实时进程。

1.2.3 时间片

  时间片的概念在文首提到过,这里不做赘述。通过前面的定义可以得知,时间片过长会导致系统对交互式处理的响应欠佳;过短又会明显增大进程切换而带来的CPU耗时(进程切换也是需要CPU参与的,会消耗相当一部分时间),而这些进程占有CPU的时间也是很短。对此,很多操作系统会设置一个默认的时间片,如10ms。但是Linux CFS调度器并没有直接分配时间片给进程,而是将CPU的使用比划分给了进程。这个比例和系统负载是密切相关的。前面讲进程优先级的时候提到多nice值,nice值表示的是时间片比例,因此,进程占用CPU的时间比还会进一步受到nice值的影响,即越高的nice值会获得占有CPU使用比越小的权重,反之则获得更高的CPU使用权重

  Linux系统处理进程调度也是用了抢占式,是否抢占当前进程,是完全由进程优先级和是否有时间片决定的。Linux中使用了新的CFS进程调度器,其抢占时机由新的可运行进程消耗了多少CPU使用比决定。如果新进程消耗的CPU使用比比例比当前进程的CPU使用比例小,那么新的进程会立马投入运行;否则,则推迟运行。关于这个可以举一个例子,压缩软件(CPU密集型,一直运行压缩算法)和文本编辑器(I/O密集型,持续等待用户输入)。假设系统中现在只有这两个进程运行,而他们的nice值又是一样的,因此,这两个进程各占CPU使用比为50%。但是由于压缩软件是CPU密集型的,因此对于它来说,肯定是占有CPU比例越多越好;而文本编辑器是I/O密集型的,大部分时间在等待用户输入(因为用户输入时间肯定没有CPU运行的快…..),所以文本编辑器占有CPU使用比肯定不会超过50%。前面讲过,CFS会有限调度占有CPU使用比的进程,文本编辑器是交互式的,因此,只要用户输入,系统会立刻抢占压缩软件,而将CPU给文本编辑器使用了。

1.2.4 公平调度

  我们知道,进程在切换时同样会带来CPU消耗,考虑到这一点,CFS在实现时首先要保证系统性能不会受损失。CFS的做法不采用给每个进程分配时间片,而是允许每个进程运行一段时间、循环轮转、选择运行最少(即占有CPU使用比最低)的进程作为下一个可运行进程。CFS在所有可运行总数的基础上计算出下一个可运行进程可以运行多久,而不是依靠nice值来计算时间片(前面讲过,nice值在CFS中被作为进程获获得处理器运行比的权重)。

二、Linux 进程调度实现

  调度实现大致如下面这4个部分组成。

- 时间记账

- 进程选择

- 调度器入口

- 睡眠和唤醒

2.1 时间记账

  - 虚拟实时。虚拟实时存放的是存放的是进程的虚拟运行时间,即记录了程序运行了多长时间以及还要运行多长时间。虚拟运行时间更加逼近CFS模型所追求的理想多任务处理器

2.2 进程选择

  其实前面已经讲过,CFS选择下一个运行进程,选择的就是那个选择运行最少(即占有CPU使用比最低)的进程作为下一个可运行进程,即虚拟实时值最小的进程。这其实就是CFS调度算法的核心:选择虚拟实时值最小的进程来投入运行。

2.3 调度器入口

  进程调度器的入口是 schedule()函数。它是内核其他部分用于调用进程调度器的入口。schedule()函数需要和一个具体的调度器类相关联,这个调度器类有属于自己的可运行进程队列。调度流程具体流程如下:**选择具有最高优先级的调度器类—选择下一个可运行的进程。

2.4 睡眠和唤醒

  休眠的进程一直处于一种不可执行状态。进程休眠是通过等待队列来处理的,进程通过如下几个步骤将自己加入等待队列中。

1. 创建等待队列

2. 将自己加入到等待队列中该队列会在进程满足条件的时候叫醒它

3. 将进程的状态变更为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE

4. 如果进程状态为TASK_INTERRUPTIBLE,则唤醒进程

5. 当进程被唤醒时,它会再次检查条件是否为真。如果是,则退出循环;如果不是,则再次调用schedule()函数并一直重复这个操作

6. 满足条件后,进程状态设置为TASK_RUNNING,并将自己移出等待队列

2.5 抢占和上下文切换

2.5.1 上下文切换

  关于上下文切换,我之前在Linux内核进程管理这篇文章中提到过。

2.5.2

  抢占分为用户抢占和内核抢占

用户抢占

  内核即将返回用户空间时,如果need_resched标志被设置,会导致schedule()被调用,此时就会发生用户抢占。用户抢占发生在以下情况:

1. 从系统调用返回用户空间时

2. 从中断处理程序返回用户空间时

内核抢占

  内核抢占发生时机:

1. 中断处理程序正在执行,并且返回内核空间之前

2. 内核代码再一次具有可抢占性的时候

3. 内核中的任务显示的调用schedule()

4. 内核中的任务阻塞

以上就是自己在学习Linux进程调度时的随记,我个人一直人为理论是实际操作的基础,只有弄清了内部运行机制,才能更好的去解决问题,尤其是对于运维同学来说,个人人为这是很重要的。共勉
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 进程调度 内核