作者:Lee Teschler
过去,在微处理器芯片刚刚问世的黑暗时代,工科大学生往往是在 DEC PDP-11 小型计算机等机器上首次尝试正经的计算机编程。除了尽力编写能够在 PDP-11 上正确运行的程序外,当时的学生还必须保证他们编写的代码紧凑。在早期计算机课程中,有一种情况会激怒老师,那就是提交一个本来用 15 行代码就可以完成的 20 行汇编码程序。他们出现这样的反应当然不是没有理由,因为当时的内存非常昂贵。PDP-11 的读/写存储器通常只能存储 4,096 个 16 位字,该存储器由 22 密耳磁芯组成,这些磁芯通过导线进行访问。
Digital Equipment Corporation (DEC) 的 PDP-11 计算机。(图片来源:flickr)
时至今日,您会发现编程课程仍然强调代码紧凑的重要性。但有迹象表明,编程课程可能很快就不再只是要求编写紧凑代码,而是还会要求编写能耗最低的软件。
计算机代码能效曾经是一个小众话题。以前主要是小型嵌入式系统的程序员对其感兴趣,因为在这类系统中,必须关注 MCU 的功耗,目的是最大限度地延长供电纽扣电池的寿命。现如今,软件能效正在占据主流。越来越多的智能手机用户避免使用计算密集型应用程序,只为了多节省一点电量。甚至基于云的系统也会注重软件能效,因为它会影响数据中心的碳排放。
乍看之下,您可能会觉得紧凑代码已经很节能。事实证明,这条经验法则有时正确,但并非总是如此。此外,计算机程序的能效通常取决于编写程序所用的语言。编译语言比解释语言或编写虚拟机的语言更节能。但即使看似相互关联的编译语言,能效也可能存在很大差异。
葡萄牙的研究人员深入分析了能源、时间和内存使用与节能编程之间的关系 (https://dl.acm.org/doi/10.1145/3136014.3136031)。他们分析了 27 种软件语言的能效性能。为此,他们使用了最先进的编译器、解释器和虚拟机,并观察了运行 13 个不同程序时发生的情况,利用这些程序比较了广泛使用的算法采用各种常用编程语言时的实现情况。
例如,用某个基准程序计算系统中多个粒子之间相互作用所需的时间。用另一个基准程序分配和释放大量二叉树。再用一个基准程序更新哈希表,并用该表来计算特定的 DNA 核苷酸序列。
研究人员发现,人们往往误以为软件的能耗与执行时间成正比:运行越快一定越好。由此认为,缩短程序的执行时间将会减少相同比例的能耗。但这种关系并不一定这么简单,因为能耗是所用功率与持续时间的乘积。因此,如果更快的程序在执行时功耗更高,则其不见得能效更高。
最终,研究人员在几个实例中发现,编程语言的能耗排名与其执行时间的排名并不相同。例如,在涉及随机 DNA 序列生成和写入的基准测试中,Fortran 被证明是能效第二高的语言,但它在执行时间方面却排在第八位。在计算二叉树时,Pascal 和 Chapel 语言的能耗相差在 10% 以内,但 Chapel 的执行时间却少了约 55%。
研究人员的一些结论并不令人惊讶。其中一项发现是:总体而言,C 语言最快且最节能(57 J,平均执行时间为 2,019 毫秒)。在 C 语言之后,执行基准测试所需能量和时间最少的四种语言分别是 Rust(59 J,2,103 毫秒)、C++(77 J,3,155 毫秒)、Ada(98 J,3,740 毫秒)和 Java (114 J,3,821 毫秒)。正如您所料,编译语言比解释语言或虚拟机语言更节能。编译程序执行解决方案平均消耗 120 J,而虚拟机和解释语言分别消耗 5,760 J 和 2,365 J。
毫无意外,能效和执行时间排在末位的五种语言均为解释语言:能耗方面:Perl (4,604 J)、Python (4,390 J)、Ruby (4,045 J)、JRuby (2,693 J) 和 Lua (2,660 J);执行时间方面:Lua (16,7416 毫秒)、Python (14,5178 毫秒)、Perl (13,2856 毫秒)、Ruby (119,832 毫秒) 和 TypeScript (93,292 毫秒)。
研究人员还指出了大部分耗散能量的去向。基于 CPU 的能耗始终占所消耗能量的大多数。平均而言,无论编译语言、解释语言还是虚拟语言,CPU 能耗几乎都高达 90%,其余为 DRAM 能耗。
总而言之,葡萄牙研究人员认为,如果开发人员只考虑执行时间和能耗,那么确定最佳软件语言相对容易。但是,如果考虑内存使用因素,则无法不假思索地做出选择。
因此,对于地球来说有一个好消息:可以通过优化软件来提高能效。对于学习编程的学生而言有一个坏消息:现在,您不仅会因为提交的程序不够紧凑而让编程老师不悦,程序的能效低也会有同样的结果。