5

我一直在为我正在编写的应用程序而苦苦挣扎,我想我开始发现我的问题是过早的优化。我完美主义的一面希望在第一次通过时就使一切都变得最佳和完美,但我发现这使设计变得相当复杂。我没有编写可以很好地完成一件简单事情的小型可测试函数,而是倾向于尽可能多地填充功能以提高效率。

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

我倾向于多次访问数据库,我认为这是正确的做法。更重要的是我完成了这个项目,我觉得我因为这样的优化而被挂断了。我的问题是:这是避免过早优化时使用的正确策略吗?

4

3 回答 3

20

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

然后,您可以在程序受分析器控制时运行自动化测试,以找出程序在哪里花费时间和/或内存。这将告诉你在哪里进行优化。

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

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


我不记得的引述来自 Mich Ravera:

如果它不起作用,那么它不起作用的速度有多快都没关系。

于 2010-06-09T01:52:36.283 回答
5

我们应该忘记小的效率,比如大约 97% 的时间:过早优化是万恶之源。——霍尔

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

然而,我看到太多的开发人员编写了对性能无知的代码——避免过早的优化并不是编写草率/懒惰/幼稚代码的借口。编写单元测试并不能阻止这一点。尽管编写单元测试的人可能是更好的编码人员,而更好的编码人员不太容易经常编写糟糕的代码。

一定要编写测试,并将性能测试包含在的利益相关者确定的场景的测试套件中。例如,检索特定供应商的 100 件打折产品,并在 3 秒内将库存水平和格式包括为 Xml

“过早优化”与“关注性能”是一回事的谬论不应该指导软件开发。——兰德尔·海德

如果您太晚离开性能问题,您可能会发现更改太难或成本太高。

一些文章

于 2010-06-09T05:25:54.623 回答
1

对我来说,Knuth 引用的关键方面是“一分钱一分货”。这就是他最终描述过早优化器的方式——当有英镑要节省时,有人为了节省便士而讨价还价,并努力维护他们的“优化”(注意他在这里如何使用引号)软件。

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

更完整的报价:

[...] 如果 n 的平均值大约为 20,并且如果在程序中执行大约一百万次搜索例程,这将显着降低整体运行速度。这种循环优化[使用 goto] 并不难学,而且正如我所说,它们只适用于程序的一小部分,但它们通常会产生大量节省。[...]

当今许多软件工程师所共有的传统智慧要求忽略小规模的效率。但我相信这只是对他们看到的一分钱一分货的愚蠢程序员所实施的滥用行为的过度反应,他们无法调试或维护他们的“优化”程序。在已建立的工程学科中,12% 的改进很容易获得,但绝不会被认为是微不足道的;我相信同样的观点应该在软件工程中占上风。当然,我不会费心在一次性工作上进行这样的优化,但是当涉及到准备高质量程序的问题时,我不想将自己限制在无法提高效率的工具上。

毫无疑问,效率的圣杯会导致滥用。程序员浪费大量时间来思考或担心程序中非关键部分的速度,而在考虑调试和维护时,这些提高效率的尝试实际上会产生强烈的负面影响。我们应该忘记小的效率,比如说 97% 的时间;过早的优化是万恶之源。

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

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

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

Knuth 建立“过早优化器”的核心是:

  1. 基于预感/迷信/人类直觉进行优化,没有过去的经验或衡量标准(盲目优化,实际上不知道自己在做什么)。
  2. 以节省几分钱而不是英镑的方式进行优化(无效的优化)。
  3. 为一切寻求绝对的终极效率峰值。
  4. 在非关键路径中寻求效率。
  5. 当您几乎无法维护/调试代码时尝试优化。

这些都与您的优化时间无关,而是经验和理解——从理解关键路径到理解实际提供性能的内容。

Knuth 的论文中没有涉及诸如测试驱动开发和对界面设计的主要关注之类的事情。这些是更现代的概念和想法。他主要专注于实施。

尽管如此,这是对 Knuth 建议的一个很好的更新——首先通过测试来寻求建立正确性,并且界面设计可以让您在不破坏一切的情况下进行优化。

如果我们尝试对 Knuth 进行现代解释,我会在其中添加“ship”。即使您正在通过衡量的收益优化软件的真正关键路径,如果世界上最快的软件永远不会发布,它也是毫无价值的。牢记这一点应该可以帮助您做出更明智的妥协。

我倾向于多次访问数据库,我认为这是正确的做法。更重要的是我完成了这个项目,我觉得我因为这样的优化而被挂断了。我的问题是:这是避免过早优化时使用的正确策略吗?

当您最了解自己的要求时,考虑到上述一些要点,这将取决于您做出最佳判断。

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

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

我完美主义的一面希望在第一次通过时就使一切都变得最佳和完美,但我发现这使设计变得相当复杂。

现在这部分听起来有点为时过早。一般来说,你的第一遍应该是简单的。简单性通常与相当快、比您想象的要快,即使您正在做一些多余的工作也是如此。

无论如何,我希望这些观点至少有助于增加一些考虑因素。

于 2016-01-07T00:07:14.277 回答