如何高效管理 CPU:并发和进程
# 4. 如何高效管理 CPU:并发和进程
接下来我们就要开始学习操作系统最核心的图像,多进程图像。我们之前讲过,多进程图像是操作系统的核心图像之一,明白了它,就明白了操作系统的一大部分,编写出操作系统也就指日可待了。
那么,为什么会有多进程图像?我们前面说过,操作系统是帮我们管理计算机硬件的,例如 CPU,内存,显卡和外设等; CPU 无疑是最核心的硬件了,操作系统的首要目标就是管理 CPU,就是在管理 CPU 的时候,引出了多进程图像,这是一个重要的概念。通过多进程,操作系统管理明白了 CPU,CPU 管理好了,其他硬件自然而然地就带动起来了,所以多进程图像是操作系统的核心图像
# 管理 CPU:从使用做起
既然多进程是因为管理 CPU 才引出来的,所以我们首先就要明白操作系统怎么管理 CPU。我们从简单的例子出发:先使用 CPU。
就好比管理一间课室,作为一个管理者,得充分利用教室。那么首先得用起来,才谈得上是管理。如果一间课室都没人使用,这个教室是可有可无的,谈不上管理。
如何使用 CPU 呢?首先我们得明白 CPU 的工作原理,我们之前讲过很多次,从图灵机开始一直到现代计算机,CPU 工作原理就是 4 个字:取指执行。 这是一个最基础的知识。
在冯诺依曼结构里,我们把一段程序放到内存里,然后设置 CPU 的初值(例如 PC 寄存器),那么 CPU 就会自动的执行程序了,例如我们执行这段程序:(左侧是指令的地址,右边是汇编指令)
50:mov ax, [100]
51: mov bx, [101]
52: add ax, bx
.....
100: 0
101:1
2
3
4
5
6
这个例子中,我们设置 PC=50,那么 CPU 就开始工作了。
CPU 会首先发出一条取指指令,要取出内存中地址为 50 的地址,CPU 会将 50 放到地址总线上;
内存得到取指的指令后,就会将内存里地址为 50 的内容放到数据总线上,传回给 CPU
CPU 得到指令后,就开始执行。这个指令是 mov ax, [100]
因此就会将地址 100 处的内容取出来,赋值给 ax。
CPU 取指后,PC 是自动累加的,当执行完指令后,就开始取指并执行下一条指令。不断取指执行,这就是 CPU 的工作原理。
CPU 就好比一个厨师,指令就好比菜谱,厨师看到菜谱的每个任务后,就开始执行。
因此,设置一个 PC 的初始地址后,CPU 就开始工作了。这就是使用 CPU 的方法,也是管理 CPU 的最简单的、最直观的方法。
# IO 指令对 CPU 的影响
这种最简单的、最直观的使用 CPU 的方法,有没什么问题?
我们用一个程序举例,来引出这个问题
int main(int argc, char* argv[])
{
int i , to, *fp, sum = 0;
to = atoi(argv[1]);
for(i=1; i<=to; i++)
{
sum = sum + i;
fprintf(fp,“%d”, sum);
}
}
2
3
4
5
6
7
8
9
10
我们可以让 PC 寄存器的值设置为这段程序的初始地址,CPU 就开始工作了。其中 fprintf 是一个 IO 指令;我们测试在大量循环的情况下,IO 指令和计算指令的执行速度有什么不同
没有 IO 指令的情况下,都是计算指令的时候,执行 107 次循环耗时 0.015 秒;那么一次循环耗时大约 0.015 秒/107
有 IO 指令的情况下,1000 次循环已经要 0.859 秒了。那么一次循环耗时大约 0.859 秒 / 103
我们可以简单的做个比值 ,用 ( 0.015 秒/107) / (0.859 秒 / 103),也就是两次循环的耗时比值
结果 5.7×105,我们可以近似看成 106 :1。
这个数字代表了什么含义?我们可以理解为,执行一次 IO 指令所花的时间,可以执行 106 个计算指令
通过这个例子,我们可以知道,IO 指令的执行特别慢。CPU 是在电路上工作的,而 IO 的话需要访问磁盘,磁盘是机械设备,机械设备当然比电子设备慢多了。
那么 IO 指令对 CPU 的效率有什么影响呢?我们再来举一个例子。假设一个程序,有 106 个计算指令,但有 1 条 IO 指令。让 CPU 执行到 IO 指令的时候,就得停止工作,等待 IO 的完成。
那么也就是说,执行这段程序的时候,CPU 只有 50% 的时间在工作,效率为 50%。
可能有人觉得能不能跳过这条 IO 指令,往下执行?当然是不可以的。有可能后续的程序,需要依赖这个 IO 指令得出来的数据。
这还是在 IO 指令的数量占比很低的情况下,CPU 的效率都已经这么低了,如果一个程序有很多的 IO 指令,那么 CPU 的工作效率可以说接近 0,大部分时间都在等待 IO。
就好比我们管理一间课室,我们可以很简单的就让它使用起来,但是如果它利用率低的话,如果一年才使用一次科室,那么它的效率是很低的。
# 如何提高 CPU 的效率
有没办法提高 CPU 的效率呢?我们可以举个生活的例子。就好比我们要烧水煮茶,我们首先得烧杯水,等水烧开是需要时间的,那我们肯定不会在一旁等水烧开,而是开始准备茶具等。等水烧开后,水壶会有提醒(类似计算机中的中断),再回去倒水。
同理,如果我们在遇到 IO 指令的情况下,能让 CPU 去执行其他程序,CPU 不就忙碌起来了?CPU 的效率也有很大的提升
也就是说,在内存里有多个程序,相互之间切换调度,CPU 就忙碌起来了。在讲操作系统的历史的时候,我们说过这个概念叫多道程序交替执行。这么一个很简单的思想,就大幅度提高了 CPU 的工作效率
我们来看多道程序下,CPU 的使用效率。举一个具体的例子:
第一部分是单道程序的执行示意图,从左往右执行,DEV1 和 DEV2 为 IO 设备,执行顺序下面的数字为时间,执行过程为 A 程序使用 CPU → A 程序使用 DEV1 → A 程序使用 CPU……………………当 A 程序执行完了,下面就是执行 B 程序
而如果是多道程序的话,在一开始的时候,B 设备要用 IO 设备,因此 CPU 交给 A 程序使用;当 A 程序执行到 DEV1 设备的时候,CPU 交由 B 程序执行……以此类推,最后我们可以算出 CPU 和 IO 的利用率:
单道程序 | 多道程序 | |
---|---|---|
CPU 利用率 | 40/80 = 50% | 40/45=89% |
DEV1 利用率 | 15/80=18.75% | 15/45=33% |
DEV2 利用率 | 25/80=31.25% | 25/45=56% |
我们可以看到 CPU 的利用率提高到了 89%,并且也带动了各个外设的使用。所以多道程序同时在内存里,同时出发,交替执行,这才是 CPU 应该工作的样子
我们称这种方法为并发。这个概念非常重要,如果要问如何管理好 CPU,答案就是并发。并发的并是同时,发是出发,所以同时出发,交替执行。
# 如何并发
那如何做到并发,就是提高 CPU 效率的核心了。实际上切换到另一个程序也很简单,修改 PC 的值就可以了。在遇到 IO 指令的时候,就切换 PC。
但是,只修改 PC 寄存器就可以了吗?肯定是不行的。如果程序 1 用到了寄存器 ax 和 bx,程序 2 也用到了并修改,那么程序 1 的执行结果就会出错。我们在切换的时候要保存程序 1 的用到的寄存器的值,
在汇编里,讲子程序的时候讲到了这一点,也叫保护现场。
举个生活的例子,比如我们正在看书,看到第 10 页,突然有人敲门,我们就会暂时放下手中的事情,去敲门;但处理完开门后,回来继续看书的话,肯定不是从头开始看,而是继续从第 10 页开始看,看的时候脑海还会回想之前场景
所以一个程序在执行的时候,切出去的时候需要记录很多信息,以备将来能返回。实际上记录的就是程序切出去的瞬间,其寄存器等信息。由此可以看到,运行中的程序和静态的程序,是不一样的。如果是一个未运行的静态程序,完全不用记录这些信息
就好比一本书,如果都没有看,那么什么都不用记录;但如果看到一半,临时放下的话,得记住看到哪里、相关的场景是什么养。
那么进程就描述了这种运行中的程序和静态程序的不一样,那么不一样主要体现为,需要用一种数据结构来存放、记录程序运行时的样子。我们把这个数据结构叫做 PCB(Process Control Block)。
# 进程的概念
既然运行中的程序,和静态的程序非常不一样,我们把运行中的程序,叫做进程。进程的概念非常重要。
# 小结
本堂课我们首先讲了操作系统要管理好 CPU,那么首先得使用 CPU;但只执行一个程序的话,CPU 的效率低,为提高效率,我们就需要交替执行多个程序,为了完成程序的切换,我们需要记录程序执行的瞬间;我们还引出了一个概念:进程。
反过来说,操作系统使用 CPU,就是启动一个进程让 CPU 执行;为了更好的管理 CPU,操作系统就启动多个进程,并让进程交替执行,这就是为什么要有多进程图像的原因,以及多进程图像的基本轮廓