我是否正确理解过早优化?

时间:2010-06-09 01:49:39

标签: premature-optimization

我一直在努力处理我正在编写的应用程序,我认为我开始发现我的问题是过早优化。我的完美主义者一方希望通过第一次使一切变得最佳和完美,但我发现这使设计变得相当复杂。我没有编写简单易行的小型可测试函数,而是倾向于尽可能多地填充功能,以提高效率。

例如,我避免多次访问数据库以获取同一条信息,代价是代码变得更加复杂。我的一部分想要不用担心冗余数据库调用。这样可以更容易地编写正确的代码,并且无论如何,所获取的数据量都很小。我的另一部分感觉非常肮脏和不干净这样做。 : - )

我倾向于多次去数据库,我认为这是正确的举措。更重要的是,我完成了项目,我觉得我因为这样的优化而陷入困境。我的问题是:这是在避免过早优化时使用的正确策略吗?

3 个答案:

答案 0 :(得分:20)

这是一般的正确策略。让代码工作,完全覆盖自动化测试。

然后,您可以在程序受分析器控制的情况下运行自动化测试,以找出程序花费时间和/或内存的位置。这将显示优化的位置。

它将向您展示如何优化工作代码,而不是将代码全部放在一起时可能有效的代码。

您不希望代码以最佳方式失败。


我不记得的一句话来自Mich Ravera:

  

如果它不起作用,它无效的速度无关紧要。

答案 1 :(得分:5)

  

我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源。 - Hoare

虽然@John Saunders指出它,但单独应用TDD可能无法完全解决您的问题。我坚持使用TDD,当你正确地进行TDD时,如果你可以有效地应用重构,你通常会得到更多更精简的代码,并且你知道它有效。那里没有争论。

但是,我看到有太多开发人员编写性能无知的代码 - 避免过早优化不是编写草率/懒惰/天真代码的借口。编写单元测试不会阻止这种情况。虽然编写单元测试的人可能是一个更好的编码器,但更好的编码器不太经常编写坏代码。

执行编写测试,执行将性能测试包含在您的利益相关者确定的方案的测试套件中。例如为特定供应商检索100个折扣产品,并在3秒内将库存水平和格式包含为Xml

  

“过早优化”与“关注性能”相同的谬论不应该指导软件开发。 - 兰德尔海德

如果你太晚出现性能问题,你可能会发现它太难了,或者太难以改变。

一些文章

答案 2 :(得分:1)

Knuth引用给我的关键方面是" penny-wise and pound-foolish" 。这就是他最终如何描述过早的优化者 - 当有大量的钱被挽救时,有人讨价还价,并努力维持他们的优化" (注意他如何在这里使用引号)软件。

我发现很多人经常只引用Knuth的一小部分论文。值得实现的是,他的论文主张使用goto来加速软件中的关键执行路径

更全面的引用:

  

[...]如果n的平均值约为20,并且如果在程序中执行大约一百万次左右的搜索程序,则这是整体运行速度的显着节省。这种循环优化[使用gotos]并不难学,正如我所说,它们只适用于程序的一小部分,但它们通常可以节省大量成本。 [...]

     

当今许多软件工程师所共有的传统智慧要求忽视小型企业的效率;但我相信   这只是对他们认为正在实施的虐待行为的过度反应   由一分钱聪明且愚蠢的程序员,谁不能调试或   保持他们的优化"程式。在已建立的工程   从未考虑过,容易获得12%的改进   边缘;我相信同样的观点应该在软件中占上风   工程。当然,我不打算进行这样的优化   一个人的工作,但当它是一个准备质量计划的问题,   我不想限制自己使用那些否认我的工具   效率。

     

毫无疑问,效率的严重性会导致滥用。   程序员浪费了大量时间思考或担心   关于,他们的程序的非关键部分的速度,以及这些   效率的尝试实际上会产生强烈的负面影响   考虑调试和维护。我们应该忘记小事了   效率,比如97%的时间;过早优化是根   万恶之物。

     

对某个部分进行先验判断往往是错误的   程序是非常关键的,因为它的普遍经验   一直在使用测量工具的程序员就是他们的   直觉猜测失败了。在使用这些工具七年之后,我确信从现在开始编写的所有编译器都应该被设计为向所有程序员提供反馈,指示他们的程序的哪些部分成本最高;实际上,除非特别关闭,否则应自动提供此反馈。

     

程序员知道他的例程的哪些部分非常重要之后,像双倍循环这样的转换将是值得的。请注意,此转换引入了go to语句 - 其他几个循环优化也是如此。

所以这来自于一个实际上非常关注微观层面性能的人,当时(优化者现在已经变得更好),正在利用goto来提高速度

这是Knuth建立过早优化者"的核心。是:

  1. 根据预感/迷信/人类直觉进行优化,没有过去的经验或测量(盲目优化而不知道你在做什么)。
  2. 以节省便士(无效优化)的方式进行优化。
  3. 寻求一切绝对最终的效率高峰。
  4. 非关键路径中寻求效率
  5. 尝试在您几乎无法维护/调试代码时进行优化。
  6. 这些都与优化的时间有关,而与经验和理解无关 - 从理解关键路径到理解实际提供的性能。

    Knuth的论文未涉及测试驱动开发和主要关注界面设计等问题。这些是更现代的概念和想法。他主要专注于实施。

    尽管如此,这是对Knuth建议的一个很好的更新 - 首先通过测试寻求建立正确性,并设计接口设计,让您在不破坏所有内容的情况下进行优化。

    如果我们尝试对Knuth应用现代解释,我会添加" ship"在那里。即使您通过测量收益优化软件的真正关键路径,如果它从未发布,世界上最快的软件也毫无价值。记住这一点应该可以帮助您做出更明智的妥协。

      

    我倾向于多次去数据库,我   认为这是正确的举措。我完成这项工作更重要   项目,我觉得我因为优化而陷入困境   像这样。我的问题是:这是正确使用的策略   避免过早优化?

    考虑到上面的一些观点,考虑到你自己的要求,你可以做出最好的判断。

    我建议的一个关键因素是,如果这是一个处理繁重负载的性能关键路径,那么设计公共接口的方式应该留有足够的优化空间。

    例如,不要设计具有客户端依赖关系的粒子系统到Particle接口。当您只有封装状态和单个粒子的实现时,这就没有优化的余地。在这种情况下,您可能必须对代码库进行级联更改才能进行优化。如果道路只有10米长,赛车就无法利用它的速度。而是设计朝向ParticleSystem接口,该接口聚合了一百万个粒子,例如,在可能的情况下处理散装粒子的更高级别的操作。如果您发现需要优化,那么您可以在不破坏设计的情况下获得充足的优化空间。

      

    我的完美主义者想要让一切都变得最佳   第一次完美,但我发现这很复杂   设计相当多。

    现在这部分听起来有点为时过早。一般来说,你的第一步应该是简单化。即使您正在做一些多余的工作,简单性通常也会比您想象的更快,更快速地进行。

    无论如何,我希望这些要点有助于至少增加一些事情来考虑。