第一章:计算机抽象
你有没有好奇过,计算机是如何读懂你写的代码的?它是如何将高级语言转换成转换成硬件调用的?大部分人只是负责调用,却并没有真正的了其的原理,这篇文章将告诉你“程序之下”还有什么以及如何定义计算机的性能。
程序之下
三层抽象
你有没有想过,你的计算机是什么?计算机,本质而言 ,由一堆硬件组合而成,处理0和1的系统。我们可以把咱的笔记本抽象成三个层次: 应用软件、系统软件、硬件。
应用软件就是程序员写的一本功能复杂的说明书,但这本说明书是用程序员的语言写的,计算机读不懂。而系统软件,就是应用软件和硬件之间的桥梁,它负责将晦涩的说明书翻译成简单易懂的01串。硬件负责执行任务,比如屏幕的显示,音乐播放以及计算。它像一个大汉,不会犯错,干起活来贼猛,但是你得用它的语言告诉它该怎么做,如何调用它的资源,它才能发挥它的优势。这三个抽象层中,哪一个最重要?答案见仁见智,不过技术发展的角度来看,最先被AI吃掉的,是最外面一层。其中有一个原因很有趣:它对我们来说最容易上手。
应用软件与大家生活最近,最常见的如各种游戏软件、社交软件、搜索引擎。系统软件,就稍微陌生一些了,很多人在使用系统软件时,一头雾水。举个列子,我还记得,我第一次使用 git 上传文件到github的时候,基于操作系统的语言,第一时间,让我难以适应。硬件,我愿称之为“熟悉的陌生人”。说它熟悉,因为很多人,都在用它(比如鼠标、键盘、屏幕),很多人也能说过它的名字(cpu, gpu), 但是你能了解他们的工作原理吗?我想答案是否定的。这也是为什么搞硬件的人很吃香,人们因为瞧不起硬件(鼠标、键盘、屏幕)或者觉得应用简单(cpu, gpu)都去搞纯软件去了。
系统软件呢?应用软件,在大框架不变的情况下,这个方向是饱和的。为什么? 我们接着往下看。系统软件有很多,其中,最重要的两个就是操作系统和编译器。 他们的主要任务就是处理基本输入和输出操作,分配外存和内存,为多个应用程序提供共享计算资源服务,换句话说,它是纯软和纯硬件之间的接口。 当前我们使用的操作系统是 Linux, IOS 和 Windows,在大根基不变的情况下,是不会出现其他操作系统的,因为工程量太大、难度高。除了华为,没人敢做,想做,和有能力做这方面的尝试。
另一个就是编译器,它将高级语言(C、C++、Java、python)等编写的程序翻译成硬件能够执行的指令,这个过程非常复杂,我们这里简要介绍,后面出一期详细介绍。
从高级语言到硬件语言
计算机只能够读懂二进制数据,并且按照指令的位段,提出相应的数据,执行对应的操作(计算、移位、存取)。如 1001010100101110 将告诉计算机将两个数相加。使用数字即表示指令又表示数据是计算机的基础。后面我会出文章详细介绍指令,感兴趣的朋友点赞关注不迷路。
很显然,一堆字符串很无聊,而且可读性很差,所以有了后来汇编器(assembler)的软件,负责将助记形式的指令,翻译成对应二进制。告诉计算机将A,B两个数相加。
add A,B --> 1001010100101110
然而,这还不够,理解上还不够直观,所以后来人们利用编译器,发明了高级编程语言如C++、C、Java等可移植语言,有一些单词和代数符号组成。编译器会将其转换成汇编语言。
A + B -->add A, B
到这里,或许你大概有头绪了。当我们运行代码的时候,我们编译器会检查语法,然后将我们编写的高级语言翻译成成汇编语言。然后在汇编器的帮助下,汇编语言会被翻译成计算能够读懂的指令。这些指令会被存在内存里,每一个时钟周期,CPU会从取出这些指令完成相应的操作。 过程如下:
性能
谈到这计算机,大家喜欢拼的就是性能。如何定义性能呢?可以像赛跑一样,我们比较执行相同的程序,然后比较执行所用的时间,也就是从速度的观点去理解,CPU常用这个方法比较。还有一种角度,即吞吐量的角度,比如一个时钟周期可以执行多少指令,GPU的核心思想就是这样。还是不太能偶理解? 比如,把450个游客从上海运到北京有很多方法,用飞机或者高铁运,或许一趟就够了;如果用小车运的话,需要来回几趟。
我们从速度的角度考虑性能:
性能 = 1 执行时间 性能= \frac{1}{执行时间} 性能=执行时间1
请看下面一个例题:
如果计算机A运行一个程序需要10秒,而计算机B需要15秒,那么计算机A比计算机B快多少?
性 能 A 性 能 B \frac{ 性能_A} {性能_B} 性能B性能A