深入Linux进程优先级:Nice值与O(1)调度器原理

1. 优先级是什么

优先级就是进程得到某种资源的先后顺序。优先级与权限的区别:

  • 优先级:能获得资源,拥有资源的先后顺序。
  • 权限:能不能获得资源。

1.1 为什么存在优先级

因为资源少,进程多。所以需要优先级来确定谁先拿资源,谁后拿资源。

2. Linux中的优先级

2.1 查看优先级

运行一个进程后使用ps命令来查看,有以下信息:

  • UID:代表执行者的身份,也就是这个进程是由哪个用户创建的。
  • PID:前面文章讲过,进程代号。
  • PPID:父进程代号。
  • PRI:进程的优先级,值越小越早被执行。
  • NI:当前进程的nice值。

2.2 PRI and NI

NI 就是所说的nice 值,表示进程可被执行的优先级的修正数值。加入nice值后使PRI 变为:<math xmlns="http://www.w3.org/1998/Math/MathML"> P R I ( n e w ) = P R I ( o l d ) + n i c e PRI(new) = PRI(old) + nice </math>PRI(new)=PRI(old)+nice

当nice值为负数,该进程优先级值就会变小,即优先级变高,则越快被执行。所以在Linux下,调整优先级就是调整nice值。

需要强调的是,进程的nice值与进程优先级不是一个概念,但是会影响到进程的优先级变化,可以理解nice值是进程优先级的修正数据。

2.3 更改nice值

使用top命令,进入后按 "r"->输入进程PID->输入nice值(注意:修改nice值需要root用户)。

查看当前进程

top命令

进入后按 r,输入当前进程PID

输入要修改的nice值(-10)

修改后

再次修改nice值为10(省略了中间过程,因为中途重启了一次进程导致PID不同)

再次修改后发现PID与NI 没有变回80和0 ,而是90和10,因为:

所以即使再次修改nice值为-15,我们所看到的就会是PRI:65NI:-15

其他修改nice值的命令:nice,renice。

2.4 nice值的范围

nice值的取值范围为 -20~19(一共40个级别) 。所以Linux的进程优先级也是有范围的:60~99(也是40个级别)

那么为什么要有范围呢?

  • 因为我们现在使用的操作系统大多数都是分时操作系统,要保证进程之间尽量的公平公正,所以优先级可以变但是要在可控的范围内变,如果优先级可以随意调整的话,那么就可能出现有的进程永远不会被调度的情况,这种情况也叫做饥饿问题

3. 竞争、独立、并行、并发

  • 竞争性:系统进程数目众多,而cpu资源只有少量,所以进程之间具有竞争属性,为了高效完成任务并且更合理的竞争资源,便有了优先级。
  • 独立性:多进程运行间独享各种资源,期间互不干扰。
  • 并行:多个进程在多个CPU下分别同时运行,称之为并行。
  • 并发:多个进程在同一个CPU下采用进程切换的方式,在一段时间内让多个进程推进,称之为并发。

4. 进程切换

CPU内寄存器就是一套存储空间,寄存器只有一套,属于CPU本身,但是寄存器内部的数据可以有很多。

当前我们使用的操作系统都是分时操作系统,每个进程都有它自己的 "时间片(可以理解为一个计数器)",当时间片到达后,进程就被操作系统从CPU中剥离,进而执行下一个进程。

当进程A暂时被切换出去时,进程A会带走并保存自己在寄存器内的上下文数据,以便下次再调度时候按照之前的逻辑继续运行。

5. 进程调度

一个CPU,一个运行队列(runqueue),在运行队列中存在一个queue[140],它的类型是struct list_head,更好理解一点可以理解成为struct task_struct*,也就是一个指针数组。

图片来源于网络

当我们创建出一个进程后,会根据它的优先级插入到指定位置,这样当CPU调度进程的时候,实际上就是按顺序调度,但是初始创建的进程优先级都是80,所以假如运行队列中只有queue[120]的位置存在大量进程,其他位置没有进程呢?岂不是还需要花时间遍历。

从图片中可以看到queue上方还有一个bitmap[5](位图),每个比特位代表了queue中对应位置是否存在进程,所以当需要调度进程时就查这一个位图,从而提升效率。

上面还有两个指针,分别是*active*expired*active指针就指向了活跃进程这个结构,*expired指向了过期进程的结构,所以:

  • CPU调度的时候,直接通过*active找到对应的queue[140],新增进程、或者时间片到了的进程,被从CPU上剥离,链入到过期进程的队列中。
  • 当活跃进程中所有进程都被执行完毕后,交换*active*expired两个指针指向的内容,从而能再次执行。

这时就可以知道为什么要有nice值了:当前进程在活跃进程时如果调整优先级还要进行移动操作,有了nice值后,只需要当前进程时间片到达后,加上nice值,按照调整后的优先级直接链入到过期进程中,等待下一轮再被调度时,就会直接按照调整后的优先级来调度。

那么在这种调度算法下会存在饥饿问题吗? 很明显不存在这种问题,因为在局部内(也就是每一轮调度)都会将当前所有进程调度完一遍后,再调度下一轮,即使某一个进程优先级特别高,但也要等上一轮调度完才能被调度,这就做到了局部上根据优先级调度,整体上不会造成饥饿问题。 这就是为什么要使用两个队列的原因。

相关推荐
jiunian_cn1 小时前
【Linux】centos软件安装
linux·运维·centos
程序员JerrySUN1 小时前
[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制
java·linux·架构
孤寂大仙v1 小时前
【计算机网络】非阻塞IO——select实现多路转接
linux·计算机网络
派阿喵搞电子2 小时前
Ubuntu下有关UDP网络通信的指令
linux·服务器·网络
Evan_ZGYF丶2 小时前
【PCIe总线】 -- PCI、PCIe相关实现
linux·嵌入式·pcie·pci
舰长1152 小时前
Ubuntu挂载本地镜像源(像CentOS 一样挂载本地镜像源)
linux·ubuntu·centos
程序员JerrySUN2 小时前
全面理解 Linux 内核性能问题:分类、实战与调优策略
java·linux·运维·服务器·单片机
huangyuchi.3 小时前
【Linux】LInux下第一个程序:进度条
linux·运维·服务器·笔记·进度条·c/c++
帽儿山的枪手3 小时前
程序员必掌握的iptables五表五链
linux·网络协议
西阳未落3 小时前
Linux(14)——库的制作与原理
linux