《C++编程规范:101条规则、准则与最佳实践》——2.4不要进行不成熟的优化

2.4不要进行不成熟的优化

摘要
拉丁谚语云,快马无需鞭策:不成熟优化的诱惑非常大,而它的无效性也同样严重。优化的第一原则就是:不要优化。优化的第二原则(仅适用于专家)是:还是不要优化。再三测试,而后优化。

讨论
正如[Stroustrup00]§6开始所引用的优美名言说的那样:

不成熟的优化是万恶之源。——Donald Knuth (引用Hoare的话)

另一方面,我们不能忽视效率。——Jon Bentley

Hoare和Knuth当然而且永远是完全正确的(见第6条和本条)。Bentley亦然(见第9条)。

我们将不成熟的优化定义为这样的行为:以性能为名,使设计或代码更加复杂,从而导致可读性更差,但是并没有经过验证的性能需求(比如实际的度量数据和与目标的比较结果)作为正当理由,因此本质上对程序没有真正的好处。毫无必要而且无法度量的优化行为其实根本不能使程序运行得更快,这种情况简直是太常见了。

请永远记住:

让一个正确的程序更快速,

比让一个快速的程序正确,要容易得太多、太多。

因此,默认时,不要把注意力集中在如何使代码更快上;首先关注的应该是使代码尽可能地清晰和易读(见第6条)。清晰的代码更容易正确编写,更容易理解,更容易重构——当然也更容易优化。使事情复杂的行为,包括优化,总是以后再进行的——而且只在必要的时候进行。

不成熟的优化经常并不能使程序更快,这主要有两方面原因。一方面,我们程序员在估计哪些代码应该更快或者更小,以及代码中哪里会成为瓶颈上名声很臭。包括本书的作者,也包括读者你。考虑一下这些事实吧:现代计算机都具有极为复杂的计算模型,经常是几个流水线处理单元并行工作,深高速缓存层次结构,猜测执行(speculative execution)[3],分支预测……这还只是CPU芯片。在硬件之上,编译器也在尽其所能地猜测,将源代码转换为最能发掘硬件潜力的机器码。而在这些复杂的架构之上,还有……还有你——程序员的猜测。所以,如果只是猜测的话,你的那些目标不明确的微观优化就很难有机会显著地改善代码。因此,优化之前必须进行度量;而度量之前必须确定优化的目标。在需求得到验证之前,注意力应该放在头号优先的事情上——为人编写代码。(当有什么人要求你进行优化的时候,请进行需求验证。)

另一方面,在现代程序中,许多操作越来越不受CPU的限制。它们可能更受内存的限制、网络的限制、硬盘的限制,需要等待Web Service,或等待数据库。即使在最好的情况下,优化这些操作的应用程序代码,也只不过能使等待操作更快。这也意味着程序员浪费了宝贵的时间去改善没有必要改善的地方,却没有进行需要的有价值的改善。

当然,迟早有一天需要优化某些代码。到那时,首先要考虑算法优化(见第7条),并尝试将优化封装和模块化(比如,用一个函数或者类,见第5条和第11条),然后在注释中清楚地说明优化的原因并列出所用算法作为参考。

初学者常犯的一个错误,就是编写新代码时着迷于进行过度优化(而且充满自信),却牺牲了代码的可理解性。这常常会产生大杂烩代码,这种代码即使开始时是正确的,也非常难以阅读和修改。(见第6条。)

通过引用传递(见第25条),优先调用前缀形式的++和--(见第28条),和使用很自然地从指尖流出的惯用法,都不属于不成熟的优化。这些都不是不成熟的优化,而是在避免不成熟的劣化(见第9条)。

示例
例inline悖论。这个例子简单阐述了不成熟的微观优化所带来的隐性代价。分析器(profiler)能够通过函数的命中计数出色地告诉我们哪些函数应该但是没有标记为inline;然而,分析器在寻找哪些函数已经标记为inline但是不应该标记方面,却极不擅长。太多的程序员习惯以优化的名义“将inline作为默认选择”,这几乎总是以更高的耦合性为代价,而换来的好处到底如何却很可疑。(这里有一个前提,编写inline在所用的编译器上确实起作用。参阅[Sutter00]、[Sutter02]和[Sutter04]。)

例外情况
在编写程序库的时候,预测哪些操作最后会用于性能敏感的代码中更加困难。但即使是程序库的编写者,在实施容易令人糊涂的优化之前,也会对很大范围内的客户代码进行性能测试。

参考文献
[Bentley00] §6 ● [Cline99] §13.01-09 ● [Kernighan99] §7 ● [Lakos96] §9.1.14 ● [Meyers97] §33 ● [Murray93] §9.9-10, §9.13 ● [Stroustrup00] §6 introduction ● [Sutter00] §30, §46 ● [Sutter02] §12 ● [Sutter04] §25

时间: 2024-11-02 21:44:59

《C++编程规范:101条规则、准则与最佳实践》——2.4不要进行不成熟的优化的相关文章

《C++编程规范:101条规则、准则与最佳实践》——第2章设计风格设计风格 C++编程规范:101条规则、准则与最佳实践 复杂性啊,愚人对你视而不见,实干家受你所累。 有些人避而远之。惟智者能够善加消除。 ——Alan Perlis 我知道,但是却又忘记了Hoare的至理名言:不成熟的优化是程

第2章设计风格 C++编程规范:101条规则.准则与最佳实践 复杂性啊,愚人对你视而不见,实干家受你所累. 有些人避而远之.惟智者能够善加消除. --Alan Perlis 我知道,但是却又忘记了Hoare的至理名言:不成熟的优化是程序设计中的万恶之源. --Donald Knuth[1] The Errors of TeX[Knuth89] 完全区分设计风格与编码风格是非常困难的.我们将一般在实际编写代码时才用得到的条款留到下一部分介绍. 本部分集中讨论适用面比一个特定的类或者函数更广的原则和

《C++编程规范:101条规则、准则与最佳实践》——第一章组织和策略问题1.1不要拘泥于小节 (又名:了解哪些东西不应该标准化)

第一章组织和策略问题 C++编程规范:101条规则.准则与最佳实践如果人们按照程序员编程的方式修建房屋,那么一只啄木鸟就能毁灭整个文明. --Gerald Weinberg[1] 为了遵从C和C++的伟大传统,我们从0开始编号.首要的指导原则,也就是第0条,阐明了我们认为对编程规范而言最为基本的建议. 接下来,这个导论性部分的其他条款将主要讲述几个精心选择的基本问题,这些问题大多数与代码本身并没有直接关系,它们讨论的是编写坚实代码所必需的工具和技术. 本部分中我们选出的最有价值条款是第0条:"不

《C++编程规范:101条规则、准则与最佳实践》——导读

前言 C++编程规范:101条规则.准则与最佳实践尽早进入正轨:以同样的方式实施同样的过程.不断积累惯用法.将其标准化.如此,你与莎士比亚之间的唯一区别将只是掌握惯用法的多少,而非词汇的多少. --Alan Perlis[1]} 标准最大的优点在于,它提供了如此多样的选择. --出处尚无定论 我们之所以编写本书,作为各开发团队编程规范的基础,有下面两个主要原因. 编程规范应该反映业界最久经考验的经验.它应该包含凝聚了经验和对语言的深刻理解的公认的惯用法.具体而言,编程规范应该牢固地建立在大量丰富

机器学习规则:ML工程最佳实践----rules_of_ml section 1【翻译】

作者:黄永刚 机器学习规则:ML工程最佳实践 本文旨在指引具有机器学习基础知识的工程师等人,更好的从机器学习的实践中收益.介绍一些应用机器学习需要遵循的规则,类似于Google C++ 风格指南等流行的编程指南.如果你已经上过机器学习相关课程或者正在从事相关的工作,那你已经满足阅读本文所需的背景知识了. Before Machine Learning Rule: #1: 不要害怕开发没有应用机器学习技术的产品 Rule: #2: 设计评价指标并设立优先级 Rule: #3: 先使用复杂的启发式规

《C++编程规范:101条规则、准则与最佳实践》——2.3编程中应知道何时和如何考虑可伸缩性

2.3编程中应知道何时和如何考虑可伸缩性 摘要小心数据的爆炸性增长:不要进行不成熟的优化,但是要密切关注渐近复杂性.处理用户数据的算法应该能够预测所处理的数据量耗费的时间,最好不差于线性关系.如果能够证明优化必要而且非常重要,尤其在数据量逐渐增长的情况下,那么应该集中精力改善算法的O(N)复杂性,而不是进行小型的优化,比如节省一个多余的加法运算. 讨论本条款阐述了第8条"不要进行不成熟的优化"和第9条"不要进行不成熟的劣化"之间的一个重要的平衡点.所以,这个条款非常

《C++编程规范:101条规则、准则与最佳实践》——2.5 不要进行不成熟的劣化

2.5 不要进行不成熟的劣化 摘要放松自己,轻松编程:在所有其他事情特别是代码复杂性和可读性都相同的情况下,一些高效的设计模式和编程惯用法会从你的指尖自然流出,而且不会比悲观的替代方案更难写.这并不是不成熟的优化,而是避免不必要的劣化(pessimization). 讨论避免不成熟的优化并不意味着必然损害性能.所谓不成熟的劣化,指的就是编写如下这些没有必要的.可能比较低效的程序. 在可以通过引用传递的时候,却定义了通过值传递的参数(见第25条).在使用前缀++操作符很合适的场合,却使用后缀版本(

《C++编程规范:101条规则、准则与最佳实践》——2.2 正确、简单和清晰第一

2.2 正确.简单和清晰第一 摘要软件简单为美(Keep It Simple Software,KISS):质量优于速度,简单优于复杂,清晰优于机巧,安全优于不安全(见第83条和第99条). 讨论简单设计和清晰代码的价值怎么强调都不过分.代码的维护者将因为你编写的代码容易理解而感谢你--而且这个维护者往往就是未来的你,要努力回忆起6个月前的所思所想.于是有了下面这些经典的格言警句. 程序必须为阅读它的人而编写,只是顺便用于机器执行.--Harold Abelson 和 Gerald Jay Su

Delphi面向对象编程的20条规则之一

问题描述 前言 大多数Delphi程序员都像使用VisualBasic那样使用他们手头上开发工具,而丝毫没有意识到Delphi的强大功能,更谈不上使用这些功能了.(写到这里,编辑惶恐的举起了手,怎么可能呢?)Delphi和VisualBasic不同,Delphi完全建立在面向对象结构上,这不仅影响到VCL的结构,而且影响到使用Delphi开发的每一个程序. 在本文中,我不想涉及到面向对象编程(OOP)的所有理论,只是提出一些简单的经验规则.希望这些规则能够帮助改善你的程序结构.无论你开发的是何种

《PostgreSQL服务器编程》一一1.8 程序设计最佳实践

1.8 程序设计最佳实践 开发应用程序软件是复杂的.一些有助于管理复杂性的方法非常流行,以至于它们被赋予容易记忆的首字母缩略词.接下来,我们就会介绍一些这样的规则,并介绍如何在服务器程序设计时更好地遵守这些规则.1.8.1 KISS--尽量简单(keep it simple stupid)成功的程序设计的一个重要技术就是编写简单的代码.也就是,你编写的代码3年以后仍然可以很容易理解,并且其他人也可以理解.这种方式并不一定总是行得通,但是尽可能用最简单的方法编写代码总是有意义的.由于各种原因,比如