上 Kent Dybvig 的编译器课程的时候,他有一次对我们说,很多编译器课程都强调“优化”,但大部分编译器的“优化”都是针对糟糕的程序员做的优化。比如 common subexpression elimination(CSE,提取共同子表达式)。本来训练有素的程序员应该避免写出重复而且耗时的表达式,自己定义变量来避免重复的计算。现在编译器却把这事揽在自己头上,好像这很重要一样。其实不是那么重要。

编译器的速度才是重要的事情。很多编译器做很多这类愚蠢的“优化”,试图把糟糕的代码变成优秀的代码,结果编译器的速度就因为这些优化降低了。每次 build 一个 project 用很长时间,这样修改代码到看结果的周期就变长了,开发效率就降低了。

所以 Chez Scheme 不强调这些普通的优化,它假设程序员具有基本的素质,能够自己避免重复而耗时的表达式。Chez Scheme 的优化大部分都是针对编译器自己生成的代码做的,比如 closure optimization,会尽量减小产生的 closure 的内存大小。这些是程序员无法控制的,所以编译器应该尽量达到最优。但这样的优化也都有一个限度,要是为了优化而让编译器变得很慢,目标程序却没有快很多,也不值得了。Chez Scheme 力争编译速度和目标程序的速度达到平衡。

结果在后来的工程实践中,我多次的领悟到这个重要的道理。

Reply to this note

Please Login to reply.

Discussion

《continuation 专项班结课》

「continuation 专项班」昨天已经结课了。这是既第一届进阶班之后,我第二次讲授深入的 continuation 内容。从无到有,我们自己实现并且理解了 CPS,call/cc 和 shift/reset 的概念。其中还是包括了 cpser,也就是传说中功的“王垠 40 行代码” 😄。

学习了这些内容对于实际编程有什么用处呢?首先我们用很短的代码(只有 14 行),实际地实现并理解了操作系统的线程是怎么回事,并且用很短的代码(还是只有 14 行)实现了 cpser,它的本质其实是编译器的核心部分。

有人可能以为这些也许太底层系统了,但这些内容其实也可以帮助理解最流行的一些 JavaScript 特性,比如 promise/async/await 之类的。比如,我们会理解下面这段结果有点出乎意料的 JS async 代码是在做什么,并且有能力自己实现 JS 的 promise/async/await 机制。

var show = console.log;

async function fact(n)

{

if (n == 0)

{

return 1;

}

else

{

return n * (await fact(n - 1));

}

}

fact(5).then(show);

fact(2).then(show);

fact(3).then(show);

fact(1).then(show);

fact(4).then(show);

可以试试看,这代码得到什么结果?