96

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

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

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

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

作为开发人员,最初的尝试哪个更好?

4

35 回答 35

123

你错过了一个。

第一个代码是为了正确,然后是为了清楚起见(当然,这两者通常是相连的!)。最后,只有当你有真正需要的真实经验证据时,你才能考虑优化。过早的优化确实是邪恶的。优化几乎总是会花费您的时间、清晰度和可维护性。你最好确保你买的是值得的东西。

请注意,好的算法几乎总能击败本地化调优。您没有理由不能拥有正确、清晰和快速的代码。你会非常幸运地开始专注于“快速”。

于 2008-10-08T18:45:56.010 回答
60

IMO 首先是明显的可读版本,直到测量性能并需要更快的版本。

于 2008-10-08T14:56:38.560 回答
46

从唐·克努特那里拿走

过早的优化是编程中万恶(或至少是大部分)的根源。

于 2008-10-08T14:59:26.823 回答
20

可读性 100%

如果你的编译器不能为你做 "x*2" => "x <<1" 优化——换一个新的编译器!

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

于 2008-10-08T14:57:34.287 回答
9

可读性肯定。除非有人抱怨,否则不要担心速度

于 2008-10-08T15:00:56.913 回答
8

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

于 2008-10-08T14:58:40.197 回答
8

可读性。

性能编码有它自己的一系列挑战。Joseph M. Newcomer 说得好

优化只有在重要时才重要。当它很重要时,它很重要,但在你知道它很重要之前,不要浪费很多时间去做。即使你知道它很重要,你也需要知道它在哪里重要。如果没有性能数据,您将不知道要优化什么,并且您可能会优化错误的东西。

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

于 2008-10-08T17:12:18.100 回答
5

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

于 2008-10-08T14:57:01.913 回答
5

我会首先考虑可读性。考虑到当今我们拥有的那种优化的语言和负载巨大的机器,我们以可读方式编写的大多数代码都会表现得不错。

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

于 2008-10-08T14:57:23.270 回答
4

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

于 2008-10-08T15:00:25.450 回答
4

在此处添加带有解释的评论将使其可读且快速。

这实际上取决于项目的类型,以及性能的重要性。如果您正在构建一个 3D 游戏,那么通常会有很多常见的优化需要在此过程中投入其中,而且没有理由不这样做(只是不要过早得意忘形)。但是,如果您正在做一些棘手的事情,请对其发表评论,以便任何看到它的人都会知道您如何以及为什么会变得棘手。

于 2008-10-08T15:09:38.317 回答
3

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

最好的办法是查看代码(或类似的成功应用程序)以检查其他开发人员是如何做到的。

于 2008-10-08T15:19:04.087 回答
3

两个都。您的代码应该平衡两者;可读性和性能。因为忽略其中任何一个都会影响项目的投资回报率,归根结底,这对你的老板来说才是最重要的。

可读性差会导致可维护性降低,从而导致在维护上花费更多资源,从而降低投资回报率。

糟糕的表现会导致投资和客户群减少,从而导致投资回报率降低。

于 2008-10-08T15:26:45.287 回答
3

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

过早的优化是万恶之源。

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

恕我直言,这是规则经常被误用作设计永远无法扩展或性能良好的软件的借口。

于 2008-10-08T15:33:52.170 回答
2

代码库越大,可读性越重要。试图理解一些微小的功能并不是那么糟糕。(特别是因为示例中的方法名称为您提供了线索。)对于刚刚放弃编码的孤独天才编写的一些史诗般的超级代码并不是那么好,因为他终于看到了他能力的复杂性,而这正是他刚刚所做的为你写的,你永远不会明白。

于 2008-10-08T14:59:46.667 回答
2

如果您担心代码的可读性,请不要犹豫,添加注释以提醒自己这样做的内容和原因。

于 2008-10-08T15:30:51.940 回答
2

如果没有可读性,当你真正需要它时,将很难获得性能提升。

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

此外,关于可读性,专业程序员应该能够阅读/理解计算机科学术语。例如,我们可以将方法命名为 enqueue 而不必说 putThisJobInWorkQueue。

于 2011-01-18T08:12:50.373 回答
1

位移与乘法是一种微不足道的优化,几乎没有任何收获。而且,正如已经指出的那样,您的编译器应该为您执行此操作。除此之外,增益是可以忽略的,就像运行这条指令的 CPU 一样。

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

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

于 2008-10-08T15:24:17.977 回答
1

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

于 2008-10-08T15:26:26.740 回答
1

您应该始终最大限度地优化,性能始终很重要。 我们今天有英国媒体报道软件的原因是大多数程序员不想做优化工作。

话虽如此,您始终可以将注释放在需要澄清的巧妙编码中。

于 2008-10-08T16:34:33.840 回答
1

如果你不知道你的瓶颈,那么优化是没有意义的。你可能已经让一个函数变得难以置信的高效(通常以某种程度的可读性为代价)只是发现那部分代码几乎没有运行过,或者它花费更多的时间访问磁盘或数据库,而不是你保存的小玩意。所以在你有一些东西要测量之前你不能进行微优化,然后你最好从可读性开始。但是,在设计整体架构时,您应该注意速度和可理解性,因为两者都会产生巨大的影响并且难以更改(取决于编码风格和方法)。

于 2008-10-08T22:01:07.113 回答
1

据估计,大约 70% 的软件成本用于维护。可读性使系统更易于维护,因此降低了软件在其生命周期内的成本。

在某些情况下,性能比可读性更重要,也就是说它们很少见。

在牺牲可读性之前,想一想“我(或您的公司)是否准备好通过这样做来处理我添加到系统中的额外成本?”

于 2008-10-09T03:35:13.320 回答
1

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

在 Jon Bentley 的“Programming Pearls”的第 6 章中,他描述了一个系统如何通过在 6 个不同的设计级别进行优化来实现 400 倍的加速。我相信,通过不关心这 6 个设计级别的性能,现代实现者可以轻松地在他们的程序中实现 2-3 个数量级的减速。

于 2008-10-13T08:30:37.907 回答
1

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

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

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

于 2008-10-13T08:55:42.130 回答
1

可读性是首要目标。

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

唯一在发展方面产生统计学显着差异的技术是……

在程序代码中添加空白行。

那些预结构化的、预面向对象的代码中可读性的提高是这些研究中提高生产力的唯一技术。

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

只有在整个项目经过单元测试并准备好进行检测时,才应该进行优化。你永远不知道你需要在哪里优化代码。

在 1970 年代后期 Kernigan 和 Plauger 的里程碑式著作 SOFTWARE TOOLS (1976) 和 SOFTWARE TOOLS IN PASCAL (1981) 中,展示了使用自顶向下设计创建结构化程序的方法。他们创建了文本处理程序:编辑器、搜索工具、代码预处理器。

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

他们能够优化这三个例程,并以合理、可管理的开发时间和成本产生提高性能的结果。

于 2008-10-24T19:58:48.183 回答
1

可读性第一。但比可读性更重要的是简单性,尤其是在数据结构方面。

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

看一下这个

于 2008-11-04T22:48:18.697 回答
0

首先写可读性,但希望读者是程序员。任何称职的程序员都应该知道乘法和位移之间的区别,或者能够阅读适当使用的三元运算符,能够查找并理解复杂的算法(您在评论您的代码对吗? ), ETC。

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

于 2008-10-08T15:11:12.697 回答
0

我想说的是可读性。

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

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

于 2008-10-08T15:35:55.440 回答
0

一个小时的处理器时间成本是多少?

一个小时的程序员时间成本是多少?

于 2008-10-08T15:43:14.723 回答
0

恕我直言,这两件事都无关紧要。您应该首先选择有效的代码,因为这比性能或阅读效果更重要。关于可读性:您的代码在任何情况下都应该始终是可读的。

但是,我看不出为什么代码无法读取并同时提供良好的性能。在您的示例中,第二个版本对我来说与第一个版本一样可读。什么是可读性较差的?如果程序员不知道左移与乘以 2 的幂相同,而右移与除以 2 的幂相同……那么,与一般可读性相比,您遇到的基本问题要多得多。

于 2008-10-08T16:16:41.550 回答
0

优先级必须是可读性。然后是性能,如果它得到很好的评论,以便维护人员知道为什么某些东西不标准。

于 2008-10-08T19:52:02.600 回答
0

大多数时候,我同意世界上大多数人的观点,即可读性更为重要。计算机比您想象的要快,而且只会越来越快,编译器会为您进行微优化,一旦您发现瓶颈在哪里,您就可以稍后对其进行优化。

但另一方面,有时,例如,如果您正在编写一个小程序,该程序将执行一些严重的数字运算或其他非交互式、计算密集型任务,您可能必须做出一些具有性能目标的高级设计决策心里。如果您稍后在这些情况下尝试优化慢速部分,您基本上最终会重写大部分代码。例如,您可以尝试将事物很好地封装在小类中,等等,但如果性能是一个非常高的优先级,您可能不得不满足于一个不那么好的设计,例如,不执行尽可能多的内存分配.

于 2008-10-08T22:41:18.640 回答
0

可读性。它将允许其他人(或以后的您自己)确定您要完成的工作。如果您后来发现确实需要担心性能,可读性将帮助您实现性能。

我还认为,通过专注于可读性,您实际上会得到更简单的代码,这很可能比更复杂的代码实现更好的性能。

于 2008-10-08T23:27:05.927 回答
0

“性能永远重要”是不正确的。如果您受 I/O 限制,则乘法速度无关紧要。

有人说“我们今天有膨胀软件的原因是大多数程序员不想做优化工作”,这当然是真的。我们有编译器来处理这些事情。

如今,任何编译器都将转换x*2x<<1.,如果它适合该架构的话。这是编译器比程序员更聪明的情况。

于 2008-10-08T23:48:02.920 回答
-4

如果你要发布你的软件,你必须关心结果,而不是过程。

用户不会阅读您的代码,他们会使用您的软件,并且他们不想因不必要的长时间等待而感到沮丧。如果您的缩进并正确注释的应用程序运行缓慢或占用大量内存,他们会讨厌您。

简而言之,考虑用户,而不是你自己,所以更喜欢性能而不是可读性。

该规则的最佳示例之一是 Quake 视频游戏。它的代码结构不佳,通常难以阅读,但它可以在 1995-1996 年的 PC 上以非常高的帧速率渲染数千个多边形。如果 Carmack 更喜欢可读性而不是性能,那么 Quake 和许多其他视频游戏,包括《使命召唤》(源自 Quake 3 引擎)就不会存在。

于 2013-01-12T17:01:07.563 回答