开发人员应该首先以可读性或性能为目标吗?[关闭]


82

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

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

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

对于技术和非技术读者来说,第一个版本都比较容易上手,但是第二个版本的性能可能更好,因为移位比乘法更简单。(目前,尽管这也是一个考虑因素,但假设编译器的优化器不会检测到该问题并对其进行优化)。

作为开发人员,最初尝试会更好吗?


有点苛刻。关于我们所有人有时关心的一个好问题。+1
Inisheer

3
这个例子显然是人为的和琐碎的。您实际上没有带硬编码乘法器的函数。
JohnMcG

1
关键是我看到很多问题,例如“ <表现是否优于<=?” 这是一个错误的问题-正确的(第一个)问题是惯用的还是常规的,然后担心性能。
JohnMcG

1
这是我在stackoverflow上阅读的最佳问题之一。这不仅影响了语言的语义,还影响了计算机的工作方式。+1
WolfmanDragon

2
@OutlawLemur我知道这一点。但是有些人问,例如使用<或<=构造循环是否更好(在后一种情况下,比较值会预先增加)。
JohnMcG 2012年

Answers:


108

你错过了一个。

首先是为了确保正确性,然后为了清晰起见(当然,两者经常相互连接!)。最后,只有当您有实际需要的真实经验证据时,才可以考虑进行优化。过早的优化确实是邪恶的。优化几乎总是会花费您时间,清晰度和可维护性。您最好确定自己购买了值得的东西。

请注意,好的算法几乎总是胜过局部调整。没有理由没有正确,清晰和快速的代码。不过,您会很幸运地到达那里,开始专注于“快速”。


这无疑是最好的答案。调整算法,而不是代码。通过细微的更改,我可以使Erastosthenes的jscript筛选器胜过其他相同的C ++版本。(不是我自己的方法,是阿特金斯筛子。)
彼得·沃恩

2
太糟糕了,您无法收藏回复。:)
Sandor Davidhazi

59

IMO首先是显而易见的可读版本,直到性能被测量并且需要更快的版本为止。


我同意。去年,除了公司的服务器端Java代码库之外,我还实现了一个主要组件,并尽力使其可读。后来发现存在性能问题,并且对其设计进行了一些重大修改,从而导致某些方面的可读性较差。
瑞安·德卢基

46

唐·克努斯那里拿走

过早的优化是编程中所有邪恶(或至少是大多数邪恶)的根源。


引文不是来自唐本身,而是来自霍尔。唐只是使它流行。检查维基百科。
kohlerm

1
它是整个段落中一个子句的选择性引用,其中包含一些非常重要的限定条件。
罗恩侯爵

19

可读性100%

如果您的编译器无法为您执行“ x * 2” =>“ x << 1”优化,请使用新的编译器!

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


8

在给定的示例中,两种情况下,有99.9999%的编译器将生成相同的代码。这说明了我的一般规则-首先编写可读性和可维护性,然后仅在需要时进行优化。


对于所示的两个示例,C编译器将编译成不同的汇编代码。第一个创建循环,第二个创建左移指令。对于所有C风格的编译器来说,这都是正确的,因为我没有测试过每个编译器,因此我无法对此做出任何保证。
WolfmanDragon

当然,对于此特定示例。在很多情况下不是这样,所以一般性问题仍然是一个好问题
Mark Ba​​ker

@WolfmanDragon,你到底在说什么?为什么“ * 2”会产生循环?当我用“ gcc -O2 -s”尝试时,在两种情况下我都会得到addl指令。
Paul Tomblin

1
如果您的编译器在该函数中创建了一个循环,建议您再安装一个编译器!
马丁·维尔坎斯


8

可读性。

为性能编码有其自身的挑战。约瑟夫·纽科默说得很好

优化仅在重要时才重要。当它很重要时,它很重要,但是除非您知道它很重要,否则不要浪费很多时间。即使您知道它很重要,也需要知道它在哪里。没有性能数据,您将不知道要优化的内容,并且可能会优化错误的内容。

结果将是晦涩难懂,难以编写,难以调试以及难以维护无法解决问题的代码。因此,它具有双重缺点:(a)增加软件开发和软件维护成本,以及(b)完全没有性能影响。


5

可读性。优化的时间就是进行Beta测试的时候。否则,您永远不会真正知道需要花些时间。


5

我会先阅读。考虑到这样的事实,由于当今我们拥有优化的语言和庞大的计算机负载,我们以可读方式编写的大多数代码都将表现出色。

在某些非常罕见的情况下,您可以确定自己会遇到一些性能瓶颈(可能来自过去的不良经验),并且设法找到了一些怪异的技巧,这些技巧可以为您带来巨大的性能优势,那。但是您应该很好地注释该代码段,这将有助于使其更具可读性。


4

在这场辩论中一个经常被忽视的因素是程序员花更多的时间浏览,理解和修改可读性较低的代码。考虑到程序员的时间每小时要花一百美元甚至更多,这是非常实际的成本。
这种直接的额外开发成本抵消了任何性能提升。


4

在评论中加上说明将使其可读且快速。

这实际上取决于项目的类型以及性能的重要性。如果您要构建3D游戏,则通常会沿途进行很多常见的优化,并且没有理由不这样做(只是不要太早地被淘汰)。但是,如果您在做棘手的事情,请对其进行评论,以便任何查看它的人都将知道您为什么以及为什么要棘手。


3

答案取决于上下文。例如,在设备驱动程序编程或游戏开发中,第二种形式是可接受的习惯用法。在业务应用程序中,没有那么多。

最好的选择是浏览代码(或在类似的成功应用程序中)以检查其他开发人员如何执行此代码。


3

使用<<将通过微优化。因此,Hoare(不是Knuts)的规则是:

过早的优化是万恶之源。

适用,那么您应该首先使用可读性更高的版本。

这是IMHO经常被误用作设计永远无法扩展或运行良好的软件的借口。


3

都。您的代码应兼顾两者;可读性和性能。因为忽略其中任何一个都会使项目的投资回报率下降,这最终对您的老板来说至关重要。

可读性差会导致可维护性下降,这会导致维护上花费更多的资源,从而降低ROI。

不良的性能会导致投资和客户基础的减少,从而降低ROI。


2

代码库越大,可读性就越关键。试图了解一些微小的功能还不错。(特别是由于示例中的“方法名称”为您提供了线索。)对于独来独往的天才写的一些史诗般的uber代码来说,它并不太好,因为他终于看到了他能力的最高复杂性,而这正是他所要表达的。为您而写,您将永远无法理解。



1

该位位移与乘法是微不足道的优化是收益旁边什么。而且,正如已经指出的那样,您的编译器应该为您执行此操作。除此之外,无论如何,该指令运行的CPU的增益都是可以忽略的。

另一方面,如果您需要执行认真的计算,则将需要正确的数据结构。但是,如果您的问题很复杂,则找出解决方案是解决问题的一部分。例如,考虑在1000000个未排序对象的数组中搜索ID号。然后重新考虑使用二叉树或哈希图。

但是,像n << C这样的优化通常可以忽略不计,并且在任何时候更改都是微不足道的。使代码可读不是。


1

这取决于需要解决的任务。通常,可读性更重要,但是当您首先考虑性能时,仍然有一些任务。在一切正常运行之后,您不能只花一天时间或进行概要分析和优化,因为优化本身可能需要从头开始重写代码的足够部分。但这在当今并不常见。


1

您应该始终最大程度地进行优化,性能始终至关重要。 我们今天有了膨胀软件的原因是,大多数程序员都不想做优化工作。

话虽如此,您始终可以在需要澄清光滑编码的地方添加注释。


我在一定程度上同意。我不认为您应该像最初提出的问题那样进行微优化。您必须以一种最佳方式使用资源的方式来设计系统。在该领域中可以获得更多的性能。
Erik van Brakel

今天我们确实有膨胀软件,但是我不怪它缺乏优化。我将其归咎于过度设计,用火箭筒打苍蝇,只需要划艇就建造远洋客轮。那当然很麻烦。
Mike Dunlavey

我同意你们俩的观点,即优化设计是第一要务。我还要说,同样的态度应该应用于软件工程过程的所有层次。如果您不愿意在代码级进行优化,那么在设计过程中可能也就缺少了。
兰斯·罗伯茨

1

如果您不了解瓶颈,则没有必要进行优化。您可能已经使一个函数难以置信的高效了(通常以某种程度的可读性为代价),却发现该部分代码几乎从未运行过,或者击中磁盘或数据库所花的时间比您节省的时间少。因此,只有在要进行一些测量之前,您才能进行微优化,然后您最好还是开始阅读。但是,在设计整体体系结构时,您应该同时兼顾速度和易懂性,因为两者都会产生巨大的影响并且难以更改(取决于编码风格和方法)。


1

据估计,软件成本中约有70%用于维护。可读性使系统易于维护,因此降低了软件的使用寿命。

在某些情况下,性能对可读性更重要,这表示它们之间相差无几。

在牺牲可读性之前,请考虑一下“我(或您的公司)是否准备通过这样做来应对我为系统增加的额外费用?”


1

我不在Google工作,所以我会选择邪恶的选择。(优化)

在乔恩·本特利(Jon Bentley)的“ Programming Pearls”第6章中,他描述了如何通过在6个不同的设计级别上进行优化来使一个系统的速度提高400倍。我相信,通过不关心这6个设计级别的性能,现代实现者可以轻松实现2-3个数量级的程序减慢。


1

正如几乎每个人在回答中所说的那样,我赞成可读性。我运行的100个项目中有99个没有硬性响应时间要求,因此这是一个简单的选择。

在开始编码之前,您应该已经知道答案。一些项目具有某些性能要求,例如“需要能够在Y(毫秒)秒内运行任务X”。如果是这样,您就有一个工作目标,并且知道何时必须进行优化。(希望)这是在项目的需求阶段确定的,而不是在编写代码时确定的。

良好的可读性和稍后进行优化的能力是适当软件设计的结果。如果您的软件设计合理,则应该能够隔离软件的各个部分,并在需要时重写它们,而不会破坏系统的其他部分。此外,我遇到的大多数真正的优化案例(忽略了一些真正的低级技巧,这些都是偶然的)都是从一种算法更改为另一种算法,或者将数据缓存到内存而不是磁盘/网络。


1

可读性是首要目标。

在1970年代,军队测试了一些当时“新”的软件开发技术(自上而下的设计,结构化编程,首席程序员团队,仅举几例),以确定其中哪些在统计上有显着差异。

唯一在发展上产生统计学差异的技术是...

将空白行添加到程序代码中。

这些预构建的,面向对象的代码中可读性的提高是这些研究中唯一提高生产率的技术。

==============

仅当对整个项目进行单元测试并准备好进行仪器测试时,才应进行优化。您永远都不知道需要在哪里优化代码。

在1970年代末的Kernigan和Plauger的地标性著作中,SOFTWARE TOOLS(1976)和SOFTWARE TOOLS IN PASCAL(1981)显示了使用自上而下的设计创建结构化程序的方法。他们创建了文本处理程序:编辑器,搜索工具,代码预处理器。

当对完成的文本格式设置功能进行INSTRUMENTED时,他们发现大部分处理时间都花在了三个执行文本输入和输出的例程中(在原始书中,io函数花费了89%的时间。在pascal书中,这些函数消耗了55%!)

他们能够优化这三个例程,并以合理,可管理的开发时间和成本获得了性能提升的结果。


1

可读性优先。但是,除了可读性之外,简单性,尤其是在数据结构方面。

我想起了一个学生在做视觉分析程序,他不明白为什么它这么慢。他只是遵循良好的编程习惯-每个像素都是一个对象,并且它通过向邻居发送消息来工作...

看一下这个


1

如果没有可读性,那么在您真正需要它时将很难获得性能改进。

只有在程序中出现问题时才应该提高性能,因为在很多地方会有瓶颈而不是这种语法。假设您在<<上获得了1ns的改善,但忽略了10分钟的IO时间。

同样,关于可读性,专业的程序员应该能够阅读/理解计算机科学术语。例如,我们可以命名一个方法入队,而不必说putThisJobInWorkQueue。


虽然我同意,但我认为您有一个不好的榜样。例如,作为一个对您的代码库一无所知的人,入队对我来说意义不大。我不想知道如何,我不想知道什么。您提供的示例说明了什么要好得多。
肖恩·斯威特

0

首先为提高可读性而写,但希望读者是程序员。任何精通此法的程序员都应该知道乘法和位移位之间的区别,或者能够读取适当使用它的三元运算符,能够查找并理解复杂的算法(您对代码的注释正确吗? )等

当然,早期的过度优化在以后需要重构时给您带来麻烦,这是很不好的,但这实际上不适用于单个方法,代码块或语句的优化。


0

我想说的是可读性。

但是在给定的示例中,我认为第二个版本已经足够可读,因为该函数的名称准确说明了函数中正在发生的事情。

如果我们总是有告诉我们的功能,它们会做什么...


0

一个小时的处理器时间花费多少?

一个小时的程序员时间要花多少钱?


最终用户一小时的时间要花多少钱?现在以用户数量为零。
gbjbaanb

gbjbaanb:完全是我的想法。Andy的评论仅适用于最终用户永远不会看到的服务,即使那样,这也不是一个很好的比较。
Erik van Brakel

0

恕我直言,这两件事都无关。首先,您应该选择可以运行的代码,因为这比性能或读取效果更重要。关于可读性:无论如何,您的代码应始终可读。

但是,我看不到为什么代码无法读取并同时提供良好的性能。在您的示例中,第二个版本对我而言具有第一个版本的可读性。什么是不太可读的?如果程序员不知道左移等于乘以2的幂,而右移等于除以2的幂...那么,那么您遇到的基本问题要比普通可读性多得多。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.