You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
9.6 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# FAQ第二期 | 世界上第一个编程语言是怎么来的?
你好我是徐文浩今天是第二期FAQ我搜集了第3讲到第6讲大家在留言区问的比较多的问题来做一次集中解答。
有些问题,可能你已经知道了答案,不妨看看和我的理解是否一样;如果这些问题刚好你也有,那可要认真看啦!
希望今天的你,也同样有收获!
* * *
## Q1为什么user + sys运行出来会比real time多呢
![](https://static001.geekbang.org/resource/image/36/4c/3665db1602c971c2cad1932ee8d0804c.png)
我们知道实际的计算机运行的过程中CPU会在多个不同的进程里面切换分配不同的时间片去执行任务。所以运行一个程序在现实中走过的时间并不是实际CPU运行这个程序所花费的时间。前者在现实中走过的时间我们叫作real time。有时候叫作wall clock time也就是墙上挂着的钟走过的时间。
而实际CPU上所花费的时间又可以分成在操作系统的系统调用里面花的sys time和用户态的程序所花的user time。如果我们只有一个CPU的话那real time >= sys time + user time 。所以,我当时在文章里给大家看了对应的示例。
不过有不少同学运行出来的结果不是这样的。这是因为现在大家都已经用上多核的CPU了。也就是同一时间有两个CPU可以同时运行任务。
你在一台多核或者多CPU的机器上运行seq和wc命令会分配到两个CPU上。虽然seq和wc这两个命令都是单线程运行的但是这两个命令在多核CPU运行的情况下会分别分配到两个不同的CPU。
于是user和sys的时间是两个CPU上运行的时间之和这就可能超过real的时间。而real只是现实时钟里走过的时间极端情况下user+sys可以到达real的两倍。
你可以运行下面这个命令,快速验证。让这个命令多跑一会儿,并且在后台运行。
```
time seq 100000000 | wc -l &
```
然后我们利用top命令查看不同进程的CPU占用情况。你会在top的前几行里看到seq和wc的CPU占用都接近100实际上它们各被分配到了一个不同的CPU执行。
我写这篇文章的时候测试时只开了一个1u的最小的虚拟机只有一个CPU所以不会遇到这个问题。
## Q2时钟周期时间和指令执行耗时有直接关系吗
![](https://static001.geekbang.org/resource/image/f9/31/f9da13f81cc676645a224b8ea6744931.png)
这个问题提的得非常好,@易儿易 同学的学习和思考都很仔细、深入。
“晶振时间与CPU执行固定指令耗时成正比”这个说法更准确一点。我们为了理解可以暂且认为是晶振在触发一条一条电路变化指令。这就好比你拨算盘的节奏一样。算盘拨得快珠算就算得快。结果就是一条简单的指令需要的时间就和一个时钟周期一样。
当然实际上这个问题要比这样一句话复杂很多。你可以仔细去读一读专栏关于CPU的章节呢。
从最简单的单指令周期CPU来说其实时钟周期应该是放下最复杂的一条指令的时间长度。但是我们现在实际用的都没有单指令周期CPU了而是采用了流水线技术。采用了流水线技术之后单个时钟周期里面能够执行的就不是一个指令了。我们会把一条机器指令拆分成很多个小步骤。不同的指令的步骤数量可能还不一样。不同的步骤的执行时间也不一样。所以一个时钟周期里面能够放下的是最耗时间的某一个指令步骤。
这样的话单看一条指令其实一定需要很多个时钟周期。也就是说从响应时间的角度来看一个时钟周期一定是不够执行一条指令的。但是呢因为有流水线我们同时又会去执行很多个指令的不同步骤。再加上后面讲的像超线程技术等等从吞吐量的角度来看我们又能够做到平均一个时钟周期里面完成指令数可以超过1。
想要准确理解CPU的性能问题请你一定去仔细读一读专栏的整个CPU的部分啊。
## Q3为什么低压主频只有标压的2/3计算向量点积的时候怎么提高性能
![](https://static001.geekbang.org/resource/image/87/6b/87e8925f9d8b12906164e17dad86626b.png)
低压和低主频都是为了减少能耗。比如Surface Go的电池很小机器的尺寸也很小。如果用上高主频性能更好了但是耗电并没有下来。
另外低电压对于CPU的工艺有更高的要求因为太低的电压可能导致电路都不能导通要高主频一样对工艺有更高的要求。所以一般低压CPU都是通过和低主频配合用在对于移动性和续航要求比较高的机器上。
向量计算是可以通过让加法也并行来优化的不过真实的CPU里面其实是通过SIMD指令来优化向量计算的我在后面也会讲到SIMD指令。
## Q4世界上第一个编程语言是怎么来的
![](https://static001.geekbang.org/resource/image/8d/75/8d8e399dfef0d4b62c34910ccd4f4d75.png)
如果你去计算机历史博物馆看一下真机就会明白第一台通用计算机ENIAC它的各种输入都是一些旋钮可以认为是类似用机器码在编程后来才有了汇编语言、C语言这样越来越高级的语言。
编程语言是自举的,指的是说,我们能用自己写出来的程序编译自己。但是自举,并不要求这门语言的**第一个**编译器就是用自己写的。
比如这里说到的Go先是有了Go语言我们通过C++写了编译器A。然后呢我们就可以用这个编译器A来编译Go语言的程序。接着我们再用Go语言写一个编译器程序B然后用A去编译B就得到了Go语言写好的编译器的可执行文件了。
这个之后我们就可以一直用B来编译未来的Go语言程序这也就实现了所谓的自举了。所以即使是自举也通常是先有了别的语言写好的编译器然后再用自己来写自己语言的编译器。
更详细的关于鸡蛋问题可以直接看Wikipedia上[这个链接](https://en.wikipedia.org/wiki/Bootstrapping_(compilers)),里面讲了多种这个问题的解决方案。
## Q5不同指令集中汇编语言和机器码的关系怎么对应的
![](https://static001.geekbang.org/resource/image/26/bc/26dbff8c5bf1f6fa4c24516cf4d911bc.png)
不同指令集里对应的汇编代码会对应这个指令集的机器码呀。大家不要把“汇编语言”当成是像C一样的一门统一编程语言。
“汇编语言”其实可以理解成“机器码”的一种别名或者书写方式,不同的指令集和体系结构的机器会有不同的“机器码”。
高级语言在转换成为机器码的时候,是通过编译器进行的,需要编译器指定编译成哪种汇编/机器码。
物理机自己执行的时候只有机器码,并不认识汇编代码。
编译器如果支持编译成不同的体系结构的汇编/机器码就要维护很多不同的对应关系表但是这个表并不会太大。以最复杂的Intel X86的指令集为例也只有2000条不同的指令而已。
## Q6某篇文章大段大段读不懂怎么办
![](https://static001.geekbang.org/resource/image/3e/f6/3eeecdd9685196f4eb2e32012dc867f6.png)
@胖胖胖 同学说得很好。在专栏最开始几篇,或者到后面比较深入的文章,很多非科班的或者基础不太好的同学,会觉得读不下去,甚至很多地方看不懂。这些其实都是正常现象。
即便我在写的时候,已经尽可能考虑得比较完善,照顾大家的情况,但是肯定无法面面俱到。在我平时学习过程遇到拦路虎的时候,我一般有两种方法,这里跟你分享一下。
第一种,硬读。
你可能说了,这也叫方法吗?没错,事实就是这样。如果这个知识点,我必须要攻克,就想要搞明白,那我就会尽我所能,去看每一个字眼,把每个不理解的地方,都一点一点搞明白。不吝啬花费时间和精力。
当然这种情况适合我对这个内容完全不了解,或者已经基本了解,现在需要进一步提升的情况下。因为,在完全不了解一个知识的时候,这个壁垒是很高的。如果不想办法突破的话,那可能就没办法了解这个新的领域。而在已经基本了解某个领域或者某块知识的情况下,我去攻克一些更高难度的知识,很多时候也需要同样的方法,我会建立在兴趣的基础上去硬读,但是之后会非常非常有成就感。
第二种,先抓主要矛盾,再抓细节问题。
很多时候,大家在对一个知识不了解的时候,会感觉很“恐慌”。其实完全没必要,大家学任何东西都是从不会到会这么一个过程。就像@胖胖胖 同学说的那样,先找出这篇文章的主干,先对这些东西有个大致的概念。如果有需要,在之后的过程中,你还会碰到,你可以再重读,加深印象。
有时候,学习知识可以尝试“短期多次”。也就是说,看完一遍之后,如果不明白,先放下,过一段时间再看一遍,如果还不明白,再过一段时间再看。这样循环几次,在大脑中发酵几次,说不定就明白了,要给大脑一个缓冲的时间。
* * *
好了,今天的答疑到这里就结束了。不知道能否帮你解决了一些疑惑和问题呢?
我会持续不断地回复留言,并把比较好的问题精选出来,作为答疑。欢迎你继续在留言区留言,和大家一起交流学习。