开发者应该先关注阅读性还是性能?

101

开发人员经常会面临两种解决问题的选择,一种是惯用的和易读的,另一种则不太直观,但性能可能更好。例如,在基于C的语言中,有两种将数字乘以2的方式:

int SimpleMultiplyBy2(int x)
{
    return x * 2; 
}

int FastMultiplyBy2(int x)
{
    return x << 1;
}

第一版本对于技术和非技术读者来说更容易理解,但是第二个版本可能会表现更好,因为位移操作比乘法操作更简单。 (目前,让我们假设编译器的优化器不会检测到这一点并进行优化,尽管这也是一个考虑因素)。

作为开发人员,初始尝试哪一个会更好?


有点苛刻。关于我们有时都会担心的问题,问得好。+1 - Inisheer
3
这个例子显然是人为编造的,而且很琐碎。你不可能真的有一个带有硬编码乘数的函数。 - JohnMcG
1
重点是,我看到很多问题像“<是否比<=更好?”这是错误的问题——正确(首要)的问题是哪个是惯用的或传统的,然后再考虑性能。 - JohnMcG
2
这是我在stackoverflow上阅读过的最好的问题之一。它深入了解了计算机的运作原理,而不仅仅是语言的语义。+1 - WolfmanDragon
2
@OutlawLemur 我知道这一点。但是有些人会问,例如,使用<或<=(在后一种情况下,比较值先递增)构建循环是否更好。 - JohnMcG
显示剩余7条评论
35个回答

128

你漏掉了一个。

首先,编码要保证正确性,然后再考虑清晰度(当然这两者通常息息相关!)。最后,只有在你确实有真正的经验证据表明你需要进行优化时,才可以考虑优化。过早的优化真的是一件坏事。优化几乎总是会花费你时间、清晰度和可维护性。你最好确定你用那些优化所获得的价值。

请注意,好的算法几乎总是胜过局部调整。你完全可以编写正确、清晰、快速的代码。但如果你一开始就专注于"快",那么你将非常幸运才能达到这个目标。


这绝对是这里最好的答案。微调算法,而不是代码。通过微小的改变,我可以使一个jscript Erastosthenes筛法比一个完全相同的C++版本表现更好。(不是Atkins筛法,而是我的自己的方法。) - Peter Wone
2
很遗憾,您无法将回复标记为收藏。 :) - Sandor Davidhazi
不正确。首先要考虑可读性。可读性与可维护性相辅相成。如果代码混乱不堪,就很难进行任何操作。其次是正确性,最后才是优化。 - ThaJay

63

在性能测试之前,首先要考虑易读性高的版本。


我同意。去年,我在公司的服务器端Java代码库中实现了一个重要组件,并尽力使其易读。后来发现存在性能问题,因此对其设计进行了重大改进,导致某些方面变得不太易读。 - Ryan Delucchi

46

引用自唐纳德·克努斯的话:

在编程中,过早地进行优化是万恶之源(或者至少是大部分万恶之源)。


这句话不是Don自己说的,而是Hoare说的。Don只是让它流行起来了。请查看维基百科。 - kohlerm
1
这是从整个段落中选择引用一个从句,其中包含一些非常重要的限定条件。 - user207421

25

易读性100%

如果您的编译器无法为您执行“x*2”=>“x<<1”的优化-请获得一个新的编译器!

还要记住,99.9%的程序时间都花在等待用户输入,等待数据库查询和等待网络响应上。除非您要多次使用20亿次以上,否则这不会引起注意。


13

重要的是易读性。除非有人抱怨速度,不用担心速度。


10

在您提供的示例中,99.9999%的编译器在这两种情况下将生成相同的代码。这表明了我的一般规则-首先编写易读性和可维护性,只有在需要时才进行优化。


C编译器将为所示的两个示例编译成不同的汇编代码。第一个创建了一个循环,而第二个创建了一个左移指令。这对于所有C风格的编译器都应该是正确的,因为我没有测试过每一个编译器,所以无法保证。 - WolfmanDragon
对于这个具体的例子,当然可以。虽然有很多情况不是这样,所以一般的问题仍然是一个好问题。 - Mark Baker
@WolfmanDragon,你在说什么鬼?为什么“* 2”会生成一个循环?当我使用“gcc -O2 -s”尝试时,在两种情况下都会得到addl指令。 - Paul Tomblin
1
如果你的编译器在那个函数里创建了一个循环,我建议你换一个编译器! - Martin Vilcans

9

易读性。

编写高性能的代码有其自身的挑战。Joseph M. Newcomer在这篇文章中说得很好:

优化只有在它真正需要的时候才有意义。当它很重要的时候,它非常重要,但在你知道它很重要之前,不要浪费太多时间去做它。即使你知道它很重要,你也需要知道它很重要的地方。如果没有性能数据,你就不会知道该优化什么,你可能会优化错误的东西。

结果是:你将得到一个晦涩、难以编写、难以调试和难以维护的代码,它不能解决你的问题。因此,它具有双重劣势:(a)增加软件开发和软件维护成本;(b)根本没有性能效果。


7

我会优先考虑可读性。鉴于我们现在拥有的优化语言和强大的计算机,我们写出可读性良好的代码通常都可以有不错的表现。

在一些非常罕见的情况下,如果你非常确定将会遇到一些性能瓶颈(也许是从以往的一些不良经历中学到的),并且你找到了一些奇怪的技巧可以给你带来巨大的性能优势,那么你可以采用这种方法。但是你应该对这段代码进行充分注释,这将有助于使它更加易读。


6

易读性。优化的时间应该是在进入测试阶段时。否则,你永远不会真正知道需要花时间来做什么。


4

在这场辩论中经常被忽视的一个因素是程序员花费额外时间来浏览、理解和修改不易读懂的代码。考虑到程序员的时间每小时价值一百美元或更高,这是一个非常实际的成本。
任何性能提升都会被开发中的这种直接额外成本所抵消。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接