编程之痛
如果,你像笔者一样,有过学习或者使用汇编语言与C、C++等语言的经历,一定对下面所说的痛苦感同身受。
汇编语言
将以二进制表示的一条条CPU的机器指令,以人类可读的方式进行表示。虽然,人类可读了,但是太底层了,要实现一个简单的需求,都要堆砌很多个指令,很繁琐,编程起来很痛苦。
只是人类可读,显然不够,因为可读的层级太底层。真正写出来的汇编程序,写起来费劲,读起来更费劲……
此外,可扩展、可移植,更是想都不用想了,也很困难。毕竟,是对照机器指令逐一映射的。
C/C++
以C/C++为代表的这些高级语言,帮我们从一条条机器指令中解放出来,人类可读的层级被拔高了一些,写起来、读起来也更加容易了。其实,Java、Python等语言,在读、写代码方面,跟C/C++没有太多的本质区别。
毕竟,任何一个编程语言需要具备的核心是相通的:数据的表达和数据的处理,仅此而已。只是,不同语言的方式不同,无明显高下之分,各有千秋。
关于最好的编程语言的论战,其实,见仁见智,更多的是对编程语言设计背后思想的认同与否。所以,当听到别人说PHP是最好的编程语言,我们不应该一上来就跳起来反驳。我们也不应该随便地说出,Python是最好的编程语言,而应该更加客观、理性的说,“Python的设计理念、思想跟我比较契合,我用起来特别舒服”,虽然说是理性、客观,其实,那还是一种感觉。
从直觉上来说,有些人不太喜欢使用C/C++,大概有以下两点:
1、开发者要担起自己的责任,内存管理,自己申请,自己释放,不要期待别人给你擦屁股;
2、可迁移性差,从整个生态来看,扩展性不及Python或者Java。
我也是出于以上两点,对C/C++有些仰视、畏惧的心理。
虚拟机的出现
责任转移:从能用到好用
一个产品好用还是不好用,其实最本质的在于,产品设计者关于各种事项的责任范围界定的问题。
如果实现同样的需求,基于产品A,用户只需要点一下按钮就可以了;基于产品B,用户需要先填入一堆表单,然后点按钮,又反复调整错误的录入,最后才能提交。对比一下,显然A更好用,B只是能用。
一个产品从能用不断迭代到好用的过程,其实就是把本来界定为是用户自己的责任范围,不断缩小再缩小,产品自身需要承担的责任不断扩大再扩大。
虚拟机:编程语言设计中的责任转移
编程语言的好用与否,也是如此。这里,需要再次强调一下,还是设计思想上的认同与否,见仁见智。
如果有的用户觉得内存管理,由自己来管理太痛苦、太麻烦;
如果有的用户觉得每次都要自己处理不同平台的移植的问题,也太通过、太麻烦。
将这些本由用户自行承担的责任,由编程语言来承接,用户只需要考虑写代码实现需求就好了。
自然而然就诞生了虚拟机的设计,比如Java虚拟机、Python虚拟机等。
由对应的虚拟机来帮助用户进行内存的申请、垃圾回收,帮助用户屏蔽硬件的差异。
Java语言在早期推广的时候,就以"Write Once, Run Everywhere"为其宣传的重要特性。
虚拟机要帮助开发者实现对硬件差异的屏蔽,自然是责任转移思想的体现;而如何才能实现对硬件差异的屏蔽,则是类比、封装的进一步应用。
如同计算机操作系统屏蔽用户对硬件的感知一样,如同汇编语言对机器指令的屏蔽一样。虚拟机的设计上,是对汇编指令、对操作系统差异的进一步屏蔽。
一般虚拟机都会提供一套统一的字节码指令,其设计上,类似于汇编指令,人类可读。不同于汇编指令的硬件相关性,字节码指令是统一的,只有一套,跟硬件、操作系统无关。
责任转移的思想是转移,而不是消失。一件事情A不做了,自然有B来把它做了。
用户编写的高级语言代码,被编译成统一的字节码指令的表示。虚拟机负责将这些字节码表示,翻译为对应的硬件相关的机器指令,然后交给特定的硬件执行。
所以,Write Once, Run Everywhere的背后,是不同操作系统、硬件平台上的虚拟机的不同实现,在默默负重前行。
一切都是Trade Off
虚拟机等责任转移所带来的便捷性,其背后是对一部分灵活性的放弃。
如果,你在自己管理内存的痛苦中苦苦挣扎,虚拟机类的Python、Java,对你来说也许是一个更好的选择;
如果,你总是要考虑跨平台移植的兼容性,虚拟机类的Python、Java,对你来说也许是一个更好的选择。
但是,如果你很享受自己管理内存使用的自由,你很享受跨平台移植的挑战,虚拟机显然不合你的胃口。
进一步抽象封装的背后,是对一部分性能的放弃。
从直接编译为机器指令然后执行,变成了编译为字节码指令,然后由虚拟机解释为机器指令,然后才能执行。
处理环节的增加,必然带来性能上的影响。
世间安得双全法。
资源、场景约束下,选择什么,放弃什么,一切都是在不断权衡、取舍。
不好的一定会不断被更好的所取代,但是,从来就没有最好的,只有在特定场景、特定需求下的更好的,最适合的才是更好的。