【linux系统编程】理解冯•诺依曼体系结构

冯•诺依曼体系结构

Von Neumann Architecture

正文开始@Assassin

目录:

  • 冯•诺依曼体系结构
    • 1. 冯•诺依曼模型:
    • 2. 冯•诺依曼体系结构推导:
    • 3. 设备的工作原理:
      • 3.1 内存:
      • 3.2 中央处理器:
      • 3.3 总线:
      • 3.4 I/O设备:
    • 4. 内存如何提高冯•诺依曼体系结构的效率:
    • 5. 体系结构相关补充:

1. 冯•诺依曼模型:

1945年,冯•诺依曼联合计算机科学家们提出了计算机系统结构具体设计的报告,其遵循图灵机的设计,并且还提出用电子元件构造计算机,同时也约定了用二进制来进行计算和存储;体系结构将计算机系统具体定义为五个部分,分别是运算器,控制器,存储器,输入设备,输出设备;其中运算器与控制器并称为中央处理器(CPU),存储器也就是我们常说的内存,常见的输出设备有键盘,鼠标,网卡,硬盘等;常见的输出设备有显示器,音响,硬盘等;
【linux系统编程】理解冯•诺依曼体系结构_第1张图片
基于冯诺依曼体系结构设计的计算机的主要特点有:

  • 以运算单元为中心
  • 采用存储程序原理
  • 存储器是按地址访问,线性编址的空间
  • 控制流由指令流产生
  • 指令由操作码和地址码组成
  • 数据以二进制编码

2. 冯•诺依曼体系结构推导:

计算机被设计出来的目的及作用就是为了解决生产活动中的实际问题,而要解决问题,首先需要将数据或者问题输入到计算机当中,所以计算机必须要有输入设备;计算机处理好对应的问题后还需将计算结果输出显示出来,所以计算机必须要有输出设备;计算机通过输入设备得到数据,数据在计算机当中进行一系列的算术运算和逻辑运算后,通过输出设备进行输出;

推导的流程图如下:
【linux系统编程】理解冯•诺依曼体系结构_第2张图片不过计算机当中只有算术运算功能和逻辑运算功能是远远不够的,计算机执行逻辑/算数操作时需要有模块对其进行控制,也就是指导计算机什么时间该做什么,该怎么做,所以自然还需要有控制功能,控制何时从输入设备获取数据,何时将处理完成的数据输出到输出设备,逻辑/算数运算的流程等;对应到C/C++当中,算术运算就相当于完成一系列的加减乘除;而逻辑运算就对应于一系列的逻辑与或非等;控制功能则可类比于C/C++当中的判断、循环以及各函数之间的调用跳转等;

推导的流程图如下:
【linux系统编程】理解冯•诺依曼体系结构_第3张图片
我们把具有算术运算功能,逻辑运算功能以及控制功能的模块集合称为中央处理器,也就是CPU(Central Processing Unit)

但如果直接将输入设备和输出设备与CPU进行交互是非常不合理的;因为输入输出设备相对于中央处理器来说是非常慢的;如果片面地这样设计的话,在当前体系结构整体呈现出来的场景就是,输入设备和输出设备IO很慢,而CPU处理数据很快,操作系统一般来说会在二者之间寻求平衡点,也就是会在速度方面做出一些权衡,我们可以类比一下木桶原理,木桶能装水的多少取决于最短的那块板子,这样一来最终整个体系所呈现出来的速度将会是很慢的,这样就大大浪费了CPU的功能,CPU长时间处于空闲状态;
【linux系统编程】理解冯•诺依曼体系结构_第4张图片
因此这种交互设计方式是极其不合理的,这时内存的出现就显得很有必要;我们试想,在速度极快的CPU和速度极慢的IO设备之间,加上一层缓冲层,缓冲层的速度介于CPU和IO设备之间;这样一来,输入设备的数据就可以先存储到内存中,内存可以充当输入设备的缓存,根据计算机的局部性原理,在CPU在进行数据获取之前就把大概率会用到的数据加载到内存中,内存的速度在一定程度上能跟CPU进行匹配;自此,CPU无需与输入设备进行直接交互,CPU直接到内存中获取数据即可,这样CPU的利用率便大大提高了。

同理,输出设备也是如此,CPU将处理完的数据缓存到内存中,而输出设备只需与内存进行交互即可,且速度也能相较CPU来说能更好地匹配;

所以内存有个特点就是,比输入设备和输出设备要快很多,但是比CPU又要慢;现在内存就处于慢设备和快设备之间,是一个不快也不慢的设备,能够在该体系结构当中就起到一个缓冲的作用;


一点总结:内存能够充当缓存的关键条件就是内存是具有一定的数据存储的能力的,所以内存预装数据是提高交互效率的秘诀。数据要进行处理,必须先预先加载到内存中,这个操作是操作系统根据局部性原理来完成的。在用户层面来看,数据的交互只是内存与CPU之间的交互,而外设与内存的交互可以和内存与CPU的交互同时进行,这样一来,效率自然就提升了。所以在我看来,内存预装载数据的能力是提升效率的关键。


这种体系结构的运行流程即:用户输入的数据先放到内存当中,CPU读取数据的时候就直接从内存当中读取;CPU处理完数据后又写回内存当中,然后内存再将数据输出到输出设备当中,最后由输出设备进行输出显示,这也是冯诺依曼体系结构的基本原理模型;
【linux系统编程】理解冯•诺依曼体系结构_第5张图片
上图是我个人感觉能比较好的展现出冯诺依曼体系结构的原理图,可以很直观地记忆理解各部分之间的关系;CPU在数据的层面上只与存储器,也就是内存打交道,不与输入输出设备进行交互;在控制层面上,CPU与存储器和输入输出设备同时打交道,能控制操作系统整体的运行思路;

3. 设备的工作原理:

更为严谨的原理图如下,图中给出了总线及寄存器的存在,这样能更好地理解工作原理:
【linux系统编程】理解冯•诺依曼体系结构_第6张图片

3.1 内存:

程序和数据都是存储在内存中,内存是按地址访问,线性编址的空间;

数据存储的单位是比特(bit),即二进制的0或1;最小的存储单位是字节(byte),1字节等于8个比特位,1 Byte = 8 bit;

内存的地址是从0开始编号的,遵从自增排列,最后一个地址为内存总字节数 - 1,这种结构可以类比编程语言里的数组,这样一来,保证了内存读写任何一个数据的速度都是一样的;

3.2 中央处理器:

中央处理器也就是我们常说的 CPU,32 位和 64 位 CPU 最主要的区别在于一次能计算多少字节数据:

  • 32 位 CPU 一次可以计算 4 个字节;
  • 64 位 CPU 一次可以计算 8 个字节;

这里的 32 位和 64 位,通常称为 CPU 的位宽;

现代 CPU 之所以要设计成 64 位,是为了能计算更大的数值,如果是 8 位的 CPU,那么一次只能计算 1 个字节 0~255 范围内的数值,这样便无法一次性完成计算 10000 * 10000 ;为了能一次性进行大数的运算,CPU 需要支持多个 Byte 一起进行计算,所以 CPU 位宽越大,可以计算的数值就越大,比如说 32 位 CPU 能计算的最大整数是 4294967295

另外,32 位 CPU 最大只能操作 4GB 内存,因此即使装了 8 GB 内存条也没啥用,而 64 位 CPU 寻址范围则很大,理论最大的寻址空间为 2 ^ 64 Byte;

CPU 内部还有一些重要的组件,常见的有寄存器控制单元运算单元等。其中,控制单元负责控制 CPU 进行工作,运算单元负责计算,而寄存器的种类有很多,每种寄存器的功能又不尽相同;

CPU 中寄存器的主要功能是存储计算时产生的数据,有些小伙伴可能好奇为啥有了内存还需要寄存器?原因很简单,因为内存离 CPU 也太远了,而寄存器就存在于 CPU 中,还紧挨着控制单元和运算单元,进行与CPU的交互自然会更快;但这里我们不难发现,计算机的内部处处都有着缓存的影子,寄存器(register)也可以看做是一种缓存;

常见的寄存器种类:

  • 通用寄存器:用来存放需要进行运算的数据,比如需要进行加和运算的两个数据
  • 程序计数器:用来存储 CPU 要执行的下一条指令「所在的内存地址」,注意不是存储了下一条要执行的指令,此时指令还在内存中,程序计数器只是存储了下一条指令的地址
  • 指令寄存器:用来存放程序计数器指向的指令,也就是指令本身,指令被执行完成之前,指令都存储在这里

3.3 总线:

总线是用于 CPU 和内存以及输入输出设备之间的通信,总线可分为 3 种:

  • 地址总线:用于指定 CPU 将要操作的内存地址
  • 数据总线:用于读写内存的数据
  • 控制总线:用于发送和接收信号,比如中断、设备复位等信号,CPU 收到信号后自然进行响应,这时也需要控制总线

当 CPU 要读写内存数据的时候,一般需要通过两个总线:

  • 首先要通过 「地址总线」 来指定内存的地址
  • 再通过 「数据总线」 来传输数据

3.4 I/O设备:

输入设备向计算机输入数据,计算机经过计算后,将数据输出给输出设备;在此操作中,如果输入设备是键盘,按下按键时是需要和 CPU 进行交互的,这时就需要用到控制总线;

常见的输出设备有键盘,鼠标,网卡,硬盘等;常见的输出设备有显示器,音响,硬盘等;

4. 内存如何提高冯•诺依曼体系结构的效率:

相信大多数人有一个疑惑就是,先将输入设备的数据交给内存,再由内存将数据交给CPU,这个过程真的比CPU直接从输入设备获取数据更快吗?

我们首先需要知道:内存具有数据存储的能力。一般来说,虽然内存的大小只有4G/8G/16G,但是既然内存有大小,那么它就有装载数据的能力,而这就是提高该体系结构效率的核心;

计算机科学中有一个很有名的名词叫做局部性原理:根据统计学原理,当一个数据正在被访问时,那么下一次有很大可能会访问其周围的数据。所以当CPU需要获取某一行数据时,内存可以将该行数据之后的数据一同加载进来,也就是说,在CPU处理该数据之前,提前将该数据缓存到内存中,而之后CPU也确实是想要处理该数据的;而CPU处理数据和内存加载数据是可以同时进行的,这样下次CPU就可以直接从内存当中获取数据。

输出数据的时候也一样,CPU处理完数据后直接将数据放到内存当中,当输出设备需要时再从内存当中获取即可,这也就有了编程语言或操作系统中常说的缓冲区的概念;例如,如果是全缓冲的话,缓冲区满了才将数据打印到屏幕上,使用fflush函数将缓冲区当中的数据提前输出之类的,都是将内存当中的数据直接拿到输出设备当中进行显示输出,当然了,缓冲区也有行缓冲无缓冲类型的区别,这里不作具体介绍;

5. 体系结构相关补充:

【linux系统编程】理解冯•诺依曼体系结构_第7张图片
根据冯诺依曼体系结构图,我们可以知道,站在硬件角度或是数据层面上,CPU只和内存打交道,外设也只和内存打交道;我们学习C语言时总是听到这么一句话,C程序运行之前必须先加载到内存中,那么为什么程序运行之前必须先加载到内存?

因为进行编译过后的可执行程序(文件)是在硬盘(外设)上的,而CPU只能从内存当中获取数据,所以必须先将硬盘上的数据加载到内存,也就是必须先将程序加载到内存,程序加载到内存中就不能简单地将其成为程序了,准确地讲是一个进程(process);QQ,网易云运行起来后也是一个进程,而我们双击他们的操作可以类比为将程序加载到内存中,使其成为一个运行起来的进程;所以说,我们个人编写好的程序运行起来之后跟日常使用的软件没有本质上的区别;

常见的输入设备和输出设备(拓展):

  • 输入设备:键盘、鼠标、网卡、硬盘、话筒、摄像头、扫描仪等
  • 输出设备:显示器、音响、网卡、硬盘、打印机等

注意: 同种设备在不同场景下可能属于输入设备,也可能属于输入设备;例如将数据写到硬盘当中的操作时,硬盘就作为输出设备;从硬盘中读取数据到内存中时,硬盘就充当输入设备;

我们知道CPU当中有寄存器,实际上寄存器不仅仅在CPU当中存在,在其他外设及内存当中也是有寄存器的。例如,当我们敲击键盘时,键盘是先将获取到的内容存储在寄存器当中,然后再通过寄存器将数据写入内存的寄存器当中,最后由内存的一些硬件电路将数据保存在合适的位置;

在物理层面上,各个硬件单元之间是通过总线连接的,外设与内存之间的总线叫做IO总线,内存与CPU之间的总线叫做系统总线。而这些总线具体可分为三种:地址总线,数据总线,控制总线;

over~

你可能感兴趣的:(linux,冯诺依曼,体系结构,操作系统)