友情提示:本文共有 1918 个字,阅读大概需要 4 分钟。
编程,实际上是一个搭积木的过程。
目标需求,就是搭积木的最终目的。
无论是第三方的框架,还是CPU的指令集,都是积木。
不同编程语言的本质区别,在于各自积木的粒度不同。
汇编的粒度是CPU的单条指令,所以它可以精确地控制内存的堆栈,和程序的执行流程。
C的粒度就要粗一些,没法像汇编一样控制的那么精细,在shellcode这种需要耍花样的地方,C语言是没法用的。
Linux上的shellcode怎么写
不过在大多数的场合,它都可以满足要求。它依然可以直接操作内存的每一个字节。
更高级的语言,一般都有面向对象机制。数据被语言本身当作一个对象,而不直接暴露底层的内存细节。这种情况下是很难直接控制内存的。
高级语言的模块细节,都依赖于C/C++写成的底层框架。例如python的深度学习模型,依赖于C++实现的tensorflow框架。
从更一般化的角度来看,一种语言并不比另一种语言更难学,也不比另一种语言更好学。因为它们都是利用现有的积木去搭目标需求,区别只在于各有各的积木,但搭法都是类似的。
也就是说,所有的编程语言都是胶水语言。
当然,如果目标需求是做一个浏览器,那么你没必要非得用汇编这种细粒度的语言去写。因为这会极大的增加编码量,还有出错率。
但如果要优化浏览器里的H264解码部分的FFT变换,那么也没法用C++去写,因为它没法直接操作CPU的MMX指令集。
在写目标需求的时候,所有语言都是胶水语言。
在设计编程语言和第三方框架的时候,实际上就是在设计各种各样的积木。积木的设计原则,就是让胶水的用量尽可能小。
所以说,第三方框架必然会随着业务需求的变化而不断的更新,使用起来也会越来越简单。
越来越难用的框架,最后肯定会没人用的。
在积木被设计好的情况下,怎么用胶水去粘目标需求,都是NP问题。
象棋肯定是设计的积木,所以下象棋本质上也是NP问题。
马为什么走日?
因为只有马走日,马的跳跃距离和灵活性才是最好的折中,棋手才最容易思考马该怎么走。即,棋手才能更好地搭积木。
马如果一下子跳3格,那么马腿就太长了。你要踩到对方的某个棋子,那个计算量太大,对人是巨大的脑力负担。
马如果一下子跳1格,就跟士一样了。攻击范围太小,威力大降。
而且和士象一样走斜对角,太过对称了,缺少变化。变化太少,就是对棋子威力的一种降低。
所以设计马这个棋子时,只能让它走日。
不管是中国象棋还是国际象棋,都是不约而同的这么设计的。
只有这么设计,棋手才更容易下出好棋来。
编程语言的设计,与棋类游戏的设计,是类似的。
第三方库的API肯定要尽量设计的简单易用,能够让程序员组合出大多数的通用需求。
编译器,实际上是对汇编程序员的一种取代。因为编译器可以使用一种指令选择算法,去自动的搭积木。
在汇编层面,积木就是一条条的CPU指令。CPU指令集一般不怎么改变,所以积木的形状是固定的。
在计算一个高级语言的算式时,这个算法就可以选尽量少的指令条数,尽量少的寄存器个数,尽量少的内存访问次数。
它不需要给出最优解,只需要给出可行解就行。
运筹学上的一个典型问题是,背包问题。就是把体积和重量不同的两种物体,装在一个背包里,让背包内的东西价值最大。
这是个排列组合问题。
排列组合的数量,与物体的个数的阶乘成正比。也就是它本身不是多项式时间可以解决的。
非多项式时间,Non-Poly,NP。
根据直觉估计,想在多项式时间内求出解来,只能是近似解,而不是最优解。因为阶乘和多项式的复杂度具有本质上的差异。
我个人认为,NP问题是没法按照求最优解的思路解决的。
否则,统计物理学就没必要去搞什么玻色-爱因斯坦统计了,直接去搞粒子的排列组合就行了。但实际上只能搞统计。
(另一种是费米-狄拉克统计,也就是费米子和玻色子分别服从的规律)
“道法自然”,既然自然界就是这么搞的,那么人类也不可能搞出新花样来。
实际中解决这类问题的常用算法就是动态规划,分几步求解,每步的求解时间是多项式的。在代码上来看,就是for循环的层数是有限的,并且没有递归。
程序员写代码的过程,本质上来说也是这么一个过程。你消耗的时间,肯定与需求本身的模块数量成比例。
程序越复杂,模块越多,写起来越慢。
但你绝对会尽量降低模块之间的耦合度,让程序变成一个动态规划问题,而不是排列组合问题。
当代码写不出来的时候,说明你设计的积木(模块)不合理,胶水太难粘了(笑)。
所以说,人类的科技史,就是把哪些东西设计成一块积木,以及怎么组合积木的历史。
积木不一定是tensorflow,也可以是三极管。
胶水不一定是python,也可以是电路板。
产物不一定是人脸识别程序,还可以是电脑。
这也是编译器的最后一个问题,即编程本身到底蕴含着什么。
想了解更多精彩内容,快来关注闲聊代码
本文如果对你有帮助,请点赞收藏《每一种编程语言都是胶水语言》,同时在此感谢原作者。