计算机是如何工作的
目录
冯诺依曼体系
CPU基本工作流程:
逻辑门
门电路
算术逻辑单元 ALU(Arithmetic&LogicUnit)
算术单元(Arithmetic Unit)
逻辑单元(Logic Unit)
ALU符号
寄存器(Register)和内存(RAM)
控制单元 CU(Control Unit)
指令(Instruction)
CPU的基本工作流程
编程语言(Program Language)
程序(Program)
编程语言的发展
操作系统(Operating System)
操作系统的核心概念:
进程/任务(Process / Task)
操作系统中内核的重要功能:进程管理
详解进程:
操作系统的进程调度关键:分时复用!
完!!!
冯诺依曼体系
现代的计算机,大多都遵守冯诺伊曼体系结构
冯诺依曼体系也称为存储程序计算机,是现代计算机体系结构的基础。
核心思想:
1.二进制:数字计算机的数值采用二进制,即以0和1来作为基础用于数值表示,这种表示方法简化了计算机的电路设计,提高了计算效率。
2.程序顺序进行:计算机按照程序的顺序执行,即预先编好程序,然后交给计算机,计算机按照程序中预先定义好的顺序来进行数值运算。
功能:
1.输入:把需要的程序和数据送至计算机中。
2.存储:具有长期记忆程序,数据,中间结果及最终运算结果的能力。
3.处理:能够完成各种算术运算,逻辑运算和数据传送等数据加工处理操作。
4.控制:能够根据需要控制程序走向,并且能够根据指令控制其各部件协调操作。
5.输出:按照要求将处理结果输出给用户。
组成:
- 运算器:用于完成各种算术运算,逻辑运算和数据传送等数据加工处理的操作。
- 控制器:用于控制程序的执行,是计算机的大脑。它与运算器一起组成计算机的中央处理器(CPU)
- 存储器:用于记忆程序和数据,程序和数据以二进制代码形式不加区别地存放在存储器当中,存放位置由地址决定。分为外存和内存,用于存储数据(使用二进制方式进行存储)
- 输入设备:如鼠标,键盘等,用于将数据和程序输入到计算机中。
- 输出设备:如显示器,打印机等,用于将数据或程序的处理结果展示给客户。
针对存储空间:
硬盘 > 内存 >> CPU
针对数据访问速度:
CPU >> 内存 > 硬盘
CPU基本工作流程:
下面以一个从无到有的过程,搭建出一个CPU:
逻辑门
电子开关 —— 机械继电器
通过电子开关,可以实现1位(bit)的看似无用的逻辑运算,但至少工作起来了。
门电路
使用电子开关构建一些有用的部件 —— 门电路。可以实现1位(bit)的基本逻辑运算。
算术逻辑单元 ALU(Arithmetic&LogicUnit)
ALU是计算机中进行算术,逻辑运算的核心部件,是计算机的数学大脑。接下来,我们可以用上面构建的逻辑门来完成一个ALU。
补充知识:
进制的理解:
算术单元(Arithmetic Unit)
负责计算机里的所有数字操作。接下来会实现一个8位(bits)的加法器,来演示整个过程。
这样,我们就有了一个8位(bits)的加法器。算术单元支持的操作并不止这些,通过继续组合逻辑门,算术单元可以做到加减乘除甚至更多的算术运算。
逻辑单元(Logic Unit)
逻辑单元主要用来进行逻辑操作,最基本的操作是与,或,非才足以,但不只是一位(bit)数的比较。
ALU符号
经过基本的逻辑门电路,我们实现了一个8位(bits)的ALU,甚至比Intel74181还强大(Intel74181只是一个4位的ALU)
寄存器(Register)和内存(RAM)
光有ALU还是不够的,无法为ALU提供存储的部件。所以还需要门电路简单说明下存储的制作。
可以利用门锁来构建需要的寄存器和内存
内存的构建比寄存器复杂一些,但基本原理一致。如此构建的内存被称为RAM,支持O(1)时间复杂度访问任意位置的数据,这也就是数组下标访问操作是O(1)的硬件支持。
控制单元 CU(Control Unit)
有了ALU,存储,还不足以让计算机工作起来,需要有一个部件来指挥ALU进行何种的运算,这个部件就是控制单元(CU)。
指令(Instruction)
所谓指令,即指导CPU进行工作的命令,由操作码 + 被操作数组成。
其中,操作码用来表示要做什么动作,被操作数是本身指令要操作的数据,可能是内存地址,也可能是寄存器编号等。
指令本身也是一个数字,用二进制形式保存在内存的某个区域之中。
CPU的基本工作流程
下面,将演示指令运行的一个周期
我们写好的C语言或者Java程序,都是先编译成可执行文件(exe,包含了这个程序运行时要执行的指令和依赖的数据),当点击exe文件运行的时候,操作系统会把exe加载到内存中,在CPU中存在一个特殊的寄存器”程序计数器“,用来保存接下来要从那个内存位置来执行指令,在exe加载到内存后就能被系统自动设置好,也就是说程序计数器此时会默认为0,从0号地址开始执行,同时随着指令的执行,这里的值也会随着更新,默认情况下,就是+1自增(即顺序执行)如果遇到跳转类语句,会被设为其他的值。
执行指令的三个重要阶段:
1.取指令(CPU从内存中读取指令内容到CPU内部(会有专门的寄存器来保存读取到的指令,不是上面所述的A B寄存器))
2.分析指令(识别该指令的功能和操作数)
3.执行指令
初始情况下,从0地址开始读取指令,以0010 1110为例来执行指令
1.取指令:取到00101110指令
2.分析指令:前四位0010为操作码,查表法案先0010是LOAD_A操作,用于将数据加载到A寄存器,也就是把地址为1110(十进制为14)的数据读取到寄存器A中
3.执行指令:把14的内存地址对应的数据0000 0011(3)寄存到存储器A中
程序计数器++,执行地址为1的指令,即0001 1111
1.取指令:取到00011111指令
2.分析指令:0001对应LOAD_B操作,也就是将1111(十进制为15)这条地址对应的数据加载到B寄存器中
3.执行指令:把15的内存对应的数据0000 1110(14)存储到寄存器B中
程序计数器++,执行地址为2的指令,1000 0100
1.取指令:取到1000 0100指令
2.分析指令:1000对应ADD操作,也就是计算两个指定寄存器的数据的和,并将结果放入第二个寄存器,01为B寄存器。00为A寄存器,所以就是将B寄存器中的数值与A寄存器中的数值相加,然后将结果存放到A寄存器中。
3.执行指令:A寄存器中数据 + B寄存器中数据 = 17(0001 0001)存放在A寄存器中
程序计数器++,执行地址为3的指令,0100 1101
1.取指令:取到0100 1101指令
2.分析指令:0100对应STORE_A操作,将数据从A寄存器写入RAM的指定地址,将A寄存器中的0001 0001(17)存储到1101(13)地址中
3.执行指令:将13号内存中的数据变为0001 0001
程序计数器++,执行地址为4的地址,对应表中数据为0000 0000,表示程序执行结束。则上述过程,完成了 3 + 14的过程。
下面来总结下执行周期经过那些阶段:
当然,电子计算器中的CPU不会像刚刚那样,靠自己来驱动这个周期的运转,而是考背后的一个时钟来进行周期驱动的。
最后,ALU + CU + 寄存器 + 时钟就组成了我们平时经常看到的一个词汇:中央处理器(Center Process Unit)CPU。
补充认识CPU:
定义与功能:CPU,是计算机系统的核心部件,负责执行计算机的基本算数,逻辑,控制和输入输出操作指令。是计算机的运算和控制核心,是信息处理,程序运行的最终执行单元。
CPU的制作工艺非常精密,现今较为出名的公司:
(1)英特尔(2)AMD(3)高通
CPU的核心参数:
两个重要指标是核心数和频率:
1.核心数:指CPU内部集成的物理核心数量。多核心CPU可以同时处理多个任务,提高整体性能。
线程数:是CPU能够同时处理的线程数量。一般先进的CPU技术(如Intel的超线程技术)允许每个物理核心处理两个或者更多的线程,被称为是逻辑核心/逻辑处理器。因此,线程数可能大于等于核心数。如图,我的电脑为16核。内核为12,逻辑处理器为16,此处采用大小核技术架构。
单核处理器与线程:一个核心只能处理一个线程
超线程技术:一个核心能处理多个线程
2.主频:是CPU的时钟频率,表示CPU在单位时间内(秒)发出的脉冲数。它决定了CPU的运算速度,主频越高,CPU的运算速度就越快。主频通常以GHz为单位。
基准速度:一般可以认为为下限速度。
实时频率/睿频(对应图中的速度,它是会动态变化的):随着频率提升,消耗的电量更高,发热更多...
CPU的频率往往都是动态变化的,会根据任务量动态调整。
计算机都由”功耗墙“,CPU温度达到一定的阈值(105摄氏度),自动降频。(散热工作做好,可以让频率达到更高的水准 --> 超频)
3.指令:(C/Java语言,程序语言编写的程序,最终都要被翻译为”CPU上执行的二进制指令“(机器语言(用二进制表示)或叫做汇编语言))。
4.寄存器:位于CPU的内部,是CPU内部存储数据的部分,具有非常高的存取速度,被用来暂时的存储数据,指令地址和状态信息,以便于CPU在执行指令的时候,能够快读访问到这些数据。
但是,存储数据,主要还是靠内存和硬盘,实际上,CPU在运算中,需要先把数据从内存中读到CPU中,才能进行运算。存储空间往往为几KB,比内存更小,速度比内存更快,成本也比内存更高,断电后会丢失。因此,CPU在计算的时候,就需要反复的从内存加载数据,效率比较有影响。
现代CPU引入了缓存来解决这一问题。
某个内存的数据,经常使用,寄存器又存不下,就可以放在缓存中。数据使用的频率越高,就往L1放,没那么高,就L3,中间就L2。
编程语言(Program Language)
上面,我们大致了解并且制作了CPU和内存,现在我们利用CPU和内存,来尝试还原一下,我们已经熟悉的编程语言。例如:Java是如何和CPU指令对应起来的。
程序(Program)
所谓程序,就算一组指令,以及这组指令要处理的数据。从狭义上来说,程序,通常表现为一组文件。
程序 = 指令 + 指令要处理的数据
jre这组文件中,保存着关于JDK程序的指令和数据。PS:JDK是由多个程序组成的,其中exe结尾的文件可以粗略的认为是按照规定格式保存的指令。
早期编程:
很久以前,那还是我用Win98的时候有次我系统崩溃了,因为我是电脑白痴,我朋友给我介 绍了⼀个高手来帮我修电脑。
他看了⼀下电脑,问我有没有98的盘,我说没有。 他想了⼀下,叫我把固定电话拿给他,我想修电脑要电话干什么,但人家是高手,我也不好 说什么,就把电话拔下来给他了。
他把电话线空着的⼀头接在电脑的⼀个插孔内,然落后入了dos,然后就开始在电话上不停的 按着键,他按键的速度异常快,但是只按0,1两个键,我搞不懂这有什么用,但也不敢问, 看了半个多小时,他还是不停的按这两个键,我徐徐的有些困,我问他这东西要搞多久,他说要几个小时,我给他倒了杯茶,就⼀个⼈去隔壁睡觉了。
醒来的时候,⼀看已经过了4个多小时,我起⾝到隔壁,看见他正在98里面调试,过了⼀会 儿,他说,你试试,我坐上椅子用了⼀下,真的好了,我当时也不懂电脑,谢过人家就走 了。 后来我慢慢对电脑有了了解,终于了解,原来当时那位高手是用机器语言编了⼀个98系统, 我后来问我朋友那位高手的下落,我朋友说前几年去了美国之后,杳无音讯...
当然,上面只是一个流传的趣味小故事,真实性有待考证,不过,最早的电脑,要进行编程,是真的需要用0 1 来进行编程的。
下图为ALtair 8800计算机,是最早的一批微型电脑。用户需要控制开关,一个bit一个bit的将程序录入电脑中。
如果要求计算机的用户都必须会使用二进制编程,那门槛实在是太高了,于是,编程语言应用而生了。
编程语言的发展
为了提升编程效率,最早创造了汇编语⾔的概念。其实汇编语⾔和机器语⾔(也就是指令)直接是完 全⼀⼀对应的,只是相对于0、1这些数字,发明了⼀些帮助⼈类记忆和理解的符号将其对应起来,也 就是我们上⾯看到的类似LOAD_A、LOAD_B等。程序员完成编程之后,需要使⽤汇编器 (assembler)将汇编语⾔翻译成机器语⾔。
虽然汇编降低了程序员的记忆成本,但要求程序还是必须掌握计算机硬件的所有知识,⽽且随着计算 机⼚商越来越多,⼀次编写的程序往往只适⽤于⼀类计算机。这个是远远不够的,所以更为⾼级的语 ⾔诞⽣了,⾼级语⾔屏蔽了硬件细节,让程序员可以站在更⾼的层⾯上思考⾃⼰的业务。这⾥以C语 ⾔为例,程序员完成程序的编写之后,需要使⽤编译器(compiler)和连接器(linker)将程序翻译成 汇编语⾔,再借助汇编器变成最终的机器语⾔。
借助封装的思想,我们学习编程变得越来越容易。不过有利则有弊,⾼度的抽象,导致很多的程序员 把计算机视为⼀个⿊箱,完全⽆法理解⾃⼰的程序是如何⼯作起来的,希望我们⼤家不要做这种程序 员。 我们使⽤的Java语⾔相对于C语⾔更⾼级⼀点,但基本抽象原理上没有太⼤的差异,我们暂时就不展 开说明了。
注意:高级语言的一条语句(Statement)往往对应很多条指令(Instruction)才能完成。
操作系统(Operating System)
操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统由:Windows系列,Unix系列,Linux系列,OSX系列,Android系列,iOS系列...
每个系统之间运行的程序都是不同的,即,系统之间是不兼容的。
举例:在windows写了一个程序,这个程序是不能直接拿到Linux等其它系统上运行的(系统内部的API存在差异)
但是对于Java这种跨平台性的语言,在Windows和Linux有着不同的JVM,这些JVM是兼容同样的字节码。
操作系统的核心概念:
一个操作系统需要做的最重要的事情就是管理
1.管理不同的硬件设备
2.给软件提供稳定的运行环境(同时运行很多程序,要做到程序之间互不干扰)
以上两点也成为”操作系统内核“,是核心功能的集合。一个完整的操作系统就算内核 + 配套的应用程序。
操作系统的定位:
操作系统会管理各种的硬件设备处理器,主存,I/O设备
操作系统给应用程序提供API,让应用程序调用,从而来完成不同的操作。
例如:println是Java标准库提供的函数。JVM中,为了实现println,就会调用操作系统提供的API,执行(Linux对应的系统api叫做write)调用系统API,程序就会进入到系统的内核中执行,此时系统就会操作对应的硬件设备来完成打印操作,操作系统管理的硬件设备有很多。
不是系统直接操作硬件,而是硬件厂商,会提供对应的”驱动程序“,操作系统其实就算通过驱动程序,间接的操作硬件设备的。
进程/任务(Process / Task)
操作系统中内核的重要功能:进程管理
所谓进程,就算正在运行的应用程序。
应用程序的两种状态:
1.没有运行时是一个exe文件,待在硬盘里,为可执行文件
2.运行的时候,exe就会被加载到内存中,并且cpu执行里面的指令,即进程。
进程都是通过操作系统来执行的,执行进程里的指令需要硬件资源。
进程是操作系统分配资源是基本单位!!!
进程是如何管理的呢?PCB(Process Control Block)
1.描述:通过结构体或类,把进程的各种属性表示出来(对于Linux系统,使用称为”PCB“(进程控制块)这样的结构体来描述进程信息的)
2.组织:通过数据结构,把多个上面的结构体,串起来,并进一步的进行各种增删改查的操作(简单理解:是通过链表的方式,把上述多个PCB串在一起,但实际上更复杂)
创建新的进程就相当于是创建了一个PCB结构体,并插入到链表中,销毁进程就相当于,删除了某个PCB对应的链表节点,并释放资源。查询进程列表,就算在遍历这个链表,依次显示出对应的信息。
详解进程:
详解PCB(Process Control Block)进程控制块
PCB是一个非常复杂的结构体,里面包含着非常多的属性,重要的如下几个
1.PID进程的标识符
同一时刻,一个机器上的多个进程之间,PID是唯一的,不会重复的,系统内部的很多操作,都是通过PID来找到对应的进程的。
2.内存指针
描述进程依赖的指令和数据都在内存中的那个区域。在运行exe程序之后,操作系统就会读取exe中的指令和数据,加载到内存中(内存地址),有了内存地址,就知道进程对应的指令和数据在系统的那个位置。侧面的表现出:进程的执行,是需要一定的内存资源的。
3.文件描述符表(顺序表 / 数组)
用来描述打开了那些文件,对应到硬盘上的数据,进程中打开了某个文件,就会在顺序表中添加义项。侧面表示出:进程的执行,是需要一定的硬盘资源的。
4.进程的状态 优先级 上下文 统称为进程的调度
计算机上同时存在很多进程,这些进程是需要同时进行的,该如何执行呢调配呢?CPU负责执行,CPU每个核心,可以执行一个进程(执行进程里的指令,执行过程就算取指令,分析指令,执行指令),上文有介绍,我的电脑是16核心,那么我的电脑只能同时执行16个进程,其他的线程怎么办?
操作系统的进程调度关键:分时复用!
现如今的操作系统,都是多任务系统,同时可以运行多个进程。分时复用简单来说,就是同一时刻,由于切换速度非常快,就相当于CPU在同时运行多个程序。以我们的视角来看,程序的确是同时执行 -- 并发执行的。(但微观上却是一个一个的接着执行的,只不过执行的速度很快,感受不到切换的间隙罢了)
现在又有了多核心的CPU,此时,每个核心和每个核心之间,微观上也能同时执行不同的进程,微观上 --> 并行执行。
并发执行:多任务在同一时间执行,强调同一时间。
并行执行:多任务在多核心上执行,强调多核心。
并发/并行执行,都是操作系统内核同一调配调度的,程序员 / 普通用户,感知不到,因此,也就同一称为”并发“,对应的变成手法,也称为”并发编程“。
进程的状态,优先级,上下文,就是用来支持并发执行的调度过程的。
进程状态:
就绪状态:随时可以被调度到CPU上执行指令的
堵塞状态:无法调度到CPU上执行,之所以阻塞,是因为要做一些其他的工作,比如进行I/O操作(读写硬盘...)我们学过的scanf,Scanner输入就是典型的阻塞状态,它会从控制台读取输入,代码执行到这样的语句时,就会被”卡住“,是等待I/O产生的阻塞,直到输入数据后,才会继续执行。
进程的优先级:
也就是CPU获取资源的先后顺序问题。
进程的上下文:
分时复用,一个进程执行一会之后,就要从CPU上调度走,过一段时间,还会再调度回CPU,就要沿着上次执行的结果(之前执行的中间结果),继续向后执行
进程的记账信息:
优先级的加持之下,使得不同的进程所能吃的资源,差异越来越大,操作系统回统计每个进程再CPU上执行的时间,从而进一步的对调度进行调整。