写在前面:这篇文章是我在学了五年计算机结果连门都没完全入后,决定重新了解“计算机”这个神奇玩意的总结笔记。不过笔者学习能力较差,学识也很浅,文中避免不了出现认知错误、逻辑不通等问题,若此文有出现哪些错误问题等,欢迎大佬指出交流改正,谢谢(*^▽^*)!!
关于CPU中用到的指令和程序
CPU特点:可编程的
指令长度:内存中地址对应的二进制指令的长度,在之前虚拟假设的CPU章节中,用到的是8位的,远远不够,现代一般扩展到了32位或64位
可变指令长度
立即值:不需要其他相关操作,跳转后可立即执行的指令,例如:JUMP 、HALT
指令集举例(在intel4004中就有46个指令,而现代计算机则存有上千个指令集):
上个章节用到的:
LOAD A:将对应地址的数据存入指定寄存器中
ADD B A :将第二个寄存器的值与第一个寄存器的值相加,并存入第一个寄存器中
STORE A:将制定寄存器中的值存入对应的内存地址
新加的:
SUB B A:将第二个寄存器的值与第一个寄存器中的值相减,并存入第一个寄存器中
JUMP 2:将内存地址跳转到对应地址,实际就是用跳转的地址覆盖指令地址寄存器中的值
JUMP_NEG 5 :当该地址的结果负数状态为真时,跳转到指定地址,该负数状态NEGATIVE就是在ALU输出结果后同时输出的状态码,用该类型指令,可实现循环以及无限循环
HALT:停止,可用于区分指令和数据
关于CPU运算速度的提高,提高指令的运行速度(在CPU中加缓存)
为了满足更大量的运算需求,必须提高计算机的运算速度
在CPU与内存(RAM)中间使用总线(BUS)连接然而两者之间的数据传输速度却大大被限制,所以为了解决这个问题,在CPU内加入了一块缓存
缓存就是将内存中的数据分块先存入缓存,CPU直接与缓存之间进行数据传输交流,当传输完成后内存继续将数据块整体放入缓存来传输
缓存命中:想要的数据已经存入缓存、
缓存未命中:想要的数据不存在于缓存
缓存与内存之间出现数据不同时解决方法:
脏位:当数据运行到脏位是,就会统一将缓存中的数据替换到内存(!!不确定自己的理解是否有误)
指令流水线
并行处理:就是在指令运算的三个阶段:取指-解码-执行实现并行处理比如:在第一条指令解码时,同时开始第二条指令的取值,在第一条指令执行时,同时开始第二条指令的解码与第三条指令的取指。
可能会出现的问题
两条指令之间依赖性过强,比如第二条指令需要用到第一条指令的执行结果才能开始允许
解决方法:乱序执行:在执行指令之前,先确定每条指令的依赖程度,在执行时,同时执行几条无依赖关系的指令
并行处理中出现条件跳转:当执行过程中,出现条件跳转,无法确定下一步该走哪条路
解决方式:推测执行:分支预测,提前判断那条线路出现的概率更大,提前运行该线路的过程,如果预测成功,那么直接进行下一步,如果失败,就删掉提前预测的结果,重新执行。
现代计算机为了提高运算速度的发展
超标量处理器:一个时钟周期内完成多条指令
多核处理器:一个CPU内多个核心
一个计算机内多个CPU
举例:
世界上速度最快的计算机:中国无锡的神威 太湖之光:40960个CPU。一个cpu内256个核,有超过一千多万个核心,一个核心的频率为1.45GHz,每秒浮点运算次数(FLOPS):9.3亿次。
设计完成底层逻辑后,如何将程序写入计算机(编程的应用发展)
最开始用到编程的行业的编程方式:可穿孔纸卡
可编程纺织机:通过可穿孔纸卡的空来控制不同线的高低,来实现不同形状花色的编织
第一个用到编程的工具:亚尔卡织布机(不能算计算机)
早期的汇总机:1890年美国进行人口普查用到了穿孔纸卡来统计人口(不能算作计算机)
用插穿孔纸卡的最大程序:1955美国空军的SAGE防控系统,主程序用到了62500张穿孔纸卡,相当于存入了5MB的数据,且不仅仅可以通过穿孔纸卡输入还可以通过穿孔纸卡输出
编程方式的发展:
插线板
使用不同程序只需要插入连接不同的线即可进行编程
可插拔的插线板:IBM403核算机:用于计算盈亏总额
世界上第一台通用电子计算机:194年的ENIAC
冯诺依曼结构:1940年末-1950年初:内存变得可用,发明了存储程序计算机,内存取代了穿孔纸卡,该计算机就用到了冯诺依曼结构,并且该结构沿用之间
一个有(ALU)的处理器+数据寄存器+指令寄存器+指令地址寄存器+内存
开关、按钮
50-60年代,为了更方便,人们使用了带有指示灯的开关和按钮代替了插线板
1975年,发明了第一款商用通用计算机:Altair 8800
该计算机就是通过按钮开关来操作存储运算数据
发售时也分了组件版和完整版两个版本,且售价只有2000左右
了解编程语言的发展(CPU的母语:二进制)
机器语言,机器码(数据过多)
用二进制编写的一条条指令,如 0010(操作码) 0001(地址码)
伪代码(操作过于繁杂)
在纸上使用语言描述并通过操作操作码表对应输入到计算机内二进制的机器码
汇编语言(还需要思考寄存器和内存的位置)
通过助记符(操作码)加数据通过汇编器转换为二进制机器码
一条汇编语言=一条机器惠玲
汇编语言有自动分析下JUMP地址,不需要了解底层跳转逻辑,使用代码自动跳转即可
例如LOAD _A 14就是一条汇编语言,对应了机器码0010 1110
高级编程语言(为了脱离底层逻辑)
第一个编译器:Hopper在1952年造出,可以实现一条编程语言指令多条机器指令
编译器:通过抽象,不再需要考虑计算机的底层细节,只需要输入对应编程语言,即可通过编译器自动转换为机器语言)
高级语言:算数语言版本0 (A-0),并未得到应用
世界上第一个编程语言:FORTRAN
IBM在1957年发布:通过编译器编译
但是仅用于IBM生产的同一台电脑,若更新系统或使用其他电脑,则无法运行
通用编程语言:(一次编译处处运行)
1959:发明了不同机器通用的普通面向商业语言-COBOL
1960年代:ALGOL、LISP、BASIC
1970年代:Pascal、C、Smalltalk
1980年代:C++、Objective-C、Perl
1990年代:Python、Ruby、Java
2000年代:Swift、C#、GO
编程语言的基本元素
语句
赋值语句
控制流语句
条件语句
if else
循环语句
for
while
函数、方法、子程序(打包代码将多条语句抽象):
实现模块化编程
现代计算机的函数集合:库
算法:解决问题的具体步骤
算法复杂度:算法的输入大小和运行步骤之间关系,表示运行速度的两集2单位O(n)
算法举例
排序算法
选择排序O(n^2):每一个数与后边的每个数作比较,符合的放前面
归并算法O(n*logn):数组大于1时,将数组一分为二,二分为四,分成最后一个里只有两个数的数组,并进行比较排序,再将比较好的数组,两两数组合并进行比较排序,多次合并排序,直到覆盖所有数组。
图搜索(找到图的最短路径)
Dijkstra算法:更新前复杂度O(n!),更新后O(n logn + i)
数据结构(算法处理数据,存在内存中的格式)
基本数据结构举例
数组(也叫列表,向量):一个个连续存储,且内存大小固定,无法随意修改中间的数值
INDEX:下标,从0开始
字符串(String):
由数字、字母、符号等组成
在内存中以0结尾
有许多操作字符串的函数,例如:strcat:连接两个字符串,并存入第一个字符串地址中
内存大小固定
矩阵多维数组表,可以是任何维度,且内存大小固定
结构体:多个不同数据类型的变量打包在一起
节点:一个地址存变量,一个地址存指针(指针是特殊变量,用于指向一个)
链表:多个节点组成,且节点的指针指向像一个节点的位置,可以动态增减大小,通过该改变指针指向的地址
循环链表:最后一个节点的指针指向第一个节点的位置
非循环链表:最后一个节点的指针为0,也就是null
队列:遵循FIFO(先进先出),有入队出队的操作
栈:遵循先进后出,有出栈pop入栈操作push
树:也就是一个节点中有多个指针指向内存地址(该结构的节点只能为单向的,只能由上至下,不能相反)
二叉树:一个节点有两个指针指向内存地址
最上面的为根节点
最底下一层为叶节点
每层节点的上一个节点为母节点
根节点下面的节点都为子节点
图:多个节点相连,且双向单向都可
红黑树、堆:未讲解
编程语言都有自己预先设定的数据结构,例如
C++有标准模板库
java有java类库