什么时候优化为时过早?

发布于 07-10 07:06 字数 1728 浏览 12 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

花期渐远2024-07-17 07:06:53

我的看法是,如果您在不知道在不同场景中可以获得多少性能的情况下优化某些内容,那么这是一种过早的优化。 代码的目标确实应该使人们最容易阅读。

The way I see it is, if you optimize something without knowing how much performance you can gain in different scenario IS a premature optimization. The goal of code should really making it easiest for human to read.

反话2024-07-17 07:06:52

Don Knuth 发起了文学编程运动,因为他相信最重要的是计算机代码的功能是将程序员的意图传达给人类读者。 任何以性能的名义使代码更难以理解的编码实践都是不成熟的优化。

某些以优化名义引入的惯用语已经变得如此流行,以至于每个人都理解它们,并且它们已经成为预期,而不是为时过早。 示例包括

  • 在 C 中使用指针算术而不是数组表示法,包括使用诸如

    for (p = q; p < lim; p++) 
      
  • 将全局变量重新绑定到局部变量 之类的习惯用法,如

    本地表、io、字符串、数学 
          = 表、io、字符串、数学 
      

超越此类惯用法,走捷径后果自负

所有优化都是不成熟的,除非

  • 程序太慢(很多人忘记了这部分)。

  • 您有一个衡量(个人资料或类似内容),表明优化可以改善情况

(也可以针对内存进行优化。)

直接回答问题:

  • 如果您的“不同”技术使程序更难以理解,那么这是一个过早的优化

编辑:针对评论,使用快速排序而不是插入排序等更简单的算法每个人都理解和期望的习语的另一个例子。 (尽管如果您编写自己的排序例程而不是使用库排序例程,人们希望您有一个非常充分的理由。)

Don Knuth started the literate programming movement because he believed that the most important function of computer code is to communicate the programmer's intent to a human reader. Any coding practice that makes your code harder to understand in the name of performance is a premature optimization.

Certain idioms that were introduced in the name of optimization have become so popular that everyone understands them and they have become expected, not premature. Examples include

  • Using pointer arithmetic instead of array notation in C, including the use of such idioms as

    for (p = q; p < lim; p++)
    
  • Rebinding global variables to local variables in Lua, as in

    local table, io, string, math
        = table, io, string, math
    

Beyond such idioms, take shortcuts at your peril.

All optimization is premature unless

  • A program is too slow (many people forget this part).

  • You have a measurement (profile or similar) showing that the optimization could improve things.

(It's also permissible to optimize for memory.)

Direct answer to question:

  • If your "different" technique makes the program harder to understand, then it's a premature optimization.

EDIT: In response to comments, using quicksort instead of a simpler algorithm like insertion sort is another example of an idiom that everyone understands and expects. (Although if you write your own sort routine instead of using the library sort routine, one hopes you have a very good reason.)

别念他2024-07-17 07:06:52

恕我直言,90% 的优化应该发生在设计阶段,基于当前的需求,更重要的是未来的需求。 如果您因为应用程序无法扩展到所需的负载而必须使用分析器,那么您就太晚了,而且 IMO 将浪费大量时间和精力,同时无法纠正问题。

通常,唯一值得的优化是那些能够在速度方面使您的性能提高一个数量级,或者在存储或带宽方面实现倍增的优化。 这些类型的优化通常与算法选择和存储策略相关,并且极难反转到现有代码中。 它们可能会影响您实施系统所用语言的决策。

因此,我的建议是,根据您的要求(而不是您的代码)尽早优化,并考虑可能延长应用程序的寿命。

IMHO, 90% of your optimization should occur at design stage, based on percieved current, and more importantly, future requirements. If you have to take out a profiler because your application doesn't scale to the required load you have left it too late, and IMO will waste a lot of time and effort while failing to correct the problem.

Typically the only optimizations that are worthwhile are those that gain you an order of magnitude performance improvement in terms of speed, or a multiplier in terms of storage or bandwidth. These types of optimizations typically relate to algorithm selection and storage strategy, and are extremely difficult to reverse into existing code. They may go as deep as influencing the decision on the language in which you implement your system.

So my advice, optimize early, based on your requirements, not your code, and look to the possible extended life of your app.

歌枕肩2024-07-17 07:06:52

如果你还没有分析过,那还为时过早。

If you haven't profiled, it's premature.

献世佛2024-07-17 07:06:52

我的问题是,如果一个特定的
技术不同但不是
特别晦涩或混乱,
这真的可以被认为是
过早优化?

嗯...所以你手头上有两种技术,成本相同(使用、阅读、修改的工作量相同),而其中一种更高效。 不,在这种情况下,使用更有效的方法还不算为时过早。

中断您的代码编写以寻找常见编程结构/库例程的替代方案,即使在某个地方存在更有效的版本,即使您知道您正在编写的内容的相对速度实际上并不重要。 .. 还为时过早。

My question is, if a particular
technique is different but not
particularly obscure or obfuscated,
can that really be considered a
premature optimisation?

Um... So you have two techniques ready at hand, identical in cost (same effort to use, read, modify) and one is more efficient. No, using the more efficient one would not, in that case, be premature.

Interrupting your code-writing to look for alternatives to common programming constructs / library routines on the off-chance that there's a more efficient version hanging around somewhere even though for all you know the relative speed of what you're writing will never actually matter... That's premature.

一抹微笑2024-07-17 07:06:52

这是我在避免过早优化的整个概念中看到的问题。

说和做之间存在脱节。

我已经做了很多性能调整,从其他设计良好的代码中挤出了很大的因素,看起来没有过早的优化。
这是一个示例。

几乎在每种情况下,次优的性能就是我所说的驰骋通用性,即使用抽象的多层类和彻底的面向对象设计,其中简单的概念可能不太优雅,但完全充足的。

在讲授这些抽象设计概念的教材中,例如通知驱动架构和信息隐藏,只需设置对象的布尔属性即可产生无限的活动连锁反应,给出的原因是什么? 效率

那么,这是否是过早的优化?

Here's the problem I see with the whole concept of avoiding premature optimization.

There's a disconnect between saying it and doing it.

I've done lots of performance tuning, squeezing large factors out of otherwise well-designed code, seemingly done without premature optimization.
Here's an example.

In almost every case, the reason for the suboptimal performance is what I call galloping generality, which is the use of abstract multi-layer classes and thorough object-oriented design, where simple concepts would be less elegant but entirely sufficient.

And in the teaching material where these abstract design concepts are taught, such as notification-driven architecture, and information-hiding where simply setting a boolean property of an object can have an unbounded ripple effect of activities, what is the reason given? Efficiency.

So, was that premature optimization or not?

最冷一天2024-07-17 07:06:52

首先,让代码运行起来。 其次,验证代码是否正确。 第三,要快。

在第 3 阶段之前完成的任何代码更改肯定是不成熟的。 我不完全确定如何对之前所做的设计选择进行分类(例如使用非常适合的数据结构),但我更喜欢使用易于编程的抽象,而不是那些性能良好的抽象,直到我在这个阶段,我可以开始使用分析并拥有正确的(尽管通常很慢)参考实现来比较结果。

First, get the code working. Second, verify that the code is correct. Third, make it fast.

Any code change that is done before stage #3 is definitely premature. I am not entirely sure how to classify design choices made before that (like using well-suited data structures), but I prefer to veer towards using abstractions taht are easy to program with rather than those who are well-performing, until I am at a stage where I can start using profiling and having a correct (though frequently slow) reference implementation to compare results with.

沙沙粒小2024-07-17 07:06:52

从数据库的角度来看,在设计阶段不考虑优化设计充其量是鲁莽。 数据库不容易重构。 一旦它们设计得很糟糕(这就是不考虑优化的设计,无论你如何试图隐藏在过早优化的废话背后),几乎永远无法从中恢复,因为数据库对于数据库来说太基础了整个系统的运行。 考虑到您期望的情况的最佳代码来正确设计,比等到有一百万个用户并且人们因为您在整个应用程序中使用光标而尖叫时要便宜得多。 其他优化,例如使用可控制代码、选择看起来最好的索引等,只有在设计时才有意义。 之所以称之为快速和肮脏是有原因的。 因为它永远无法很好地工作,所以不要用快速性来代替好的代码。 另外坦率地说,当您了解数据库中的性能调优时,您可以在相同或更少的时间内编写更有可能性能良好的代码,而不是编写性能不佳的代码。 不花时间学习什么是性能良好的数据库设计是开发人员的懒惰,而不是最佳实践。

From a database perspective, not to consider optimal design at the design stage is foolhardy at best. Databases do not refactor easily. Once they are poorly designed (this is what a design that doesn't consider optimization is no matter how you might try to hide behind the nonsense of premature optimization), is almost never able to recover from that becasue the database is too basic to the operation of the whole system. It is far less costly to design correctly considering the optimal code for the situation you expect than to wait until the there are a million users and people are screaming becasue you used cursors throughout the application. Other optimizations such as using sargeable code, selecting what look to be the best possible indexes, etc. only make sense to do at design time. There is a reason why quick and dirty is called that. Because it can't work well ever, so don't use quickness as a substitute for good code. Also frankly when you understand performance tuning in databases, you can write code that is more likely to perform well in the same time or less than it takes to write code which doesn't perform well. Not taking the time to learn what is good performing database design is developer laziness, not best practice.

风轻花落早2024-07-17 07:06:52

您似乎在谈论的是优化,例如在完成大量键查找时使用基于散列的查找容器与索引容器(例如数组)。 这不是过早的优化,而是您应该在设计阶段决定的事情。

Knuth 规则涉及的优化类型是最小化最常见代码路径的长度,通过例如在汇编中重写或简化代码来优化运行最多的代码,使其不那么通用。 但是,除非您确定代码的哪些部分需要这种优化,并且优化将(可能?)使代码更难以理解或维护,否则这样做是没有用的,因此“过早的优化是万恶之源”。

Knuth 还表示,改变程序使用的算法以及解决问题的方法总是比优化更好。 例如,稍微调整一下就可以通过优化使速度提高 10%,而从根本上改变程序的工作方式可能会使速度提高 10 倍。

针对此问题上发布的许多其他评论:算法选择!=优化

What you seem to be talking about is optimization like using a hash-based lookup container vs an indexed one like an array when a lot of key lookups will be done. This is not premature optimization, but something you should decide in the design phase.

The kind of optimization the Knuth rule is about is minimizing the length the most common codepaths, optimizing the code that is run most by for example rewriting in assembly or simplifying the code, making it less general. But doing this has no use until you are certain which parts of code need this kind of optimization and optimizing will (could?) make the code harder to understand or maintain, hence "premature optimization is the root of all evil".

Knuth also says it is always better to, instead of optimizing, change the algorithms your program uses, the approach it takes to a problem. For example whereas a little tweaking might give you a 10% increase of speed with optimization, changing fundamentally the way your program works might make it 10x faster.

In reaction to a lot of the other comments posted on this question: algorithm selection != optimization

℡寂寞咖啡2024-07-17 07:06:52

该格言的要点是,通常,优化是令人费解且复杂的。 通常,架构师/设计师/程序员/维护人员需要清晰简洁的代码才能理解正在发生的事情。

如果某个特定的优化清晰简洁,请随意尝试(但请返回并检查该优化是否有效)。 关键是在整个开发过程中保持代码清晰简洁,直到性能带来的好处超过编写和维护优化所带来的成本。

The point of the maxim is that, typically, optimization is convoluted and complex. And typically, you the architect/designer/programmer/maintainer need clear and concise code in order to understand what is going on.

If a particular optimization is clear and concise, feel free to experiment with it (but do go back and check whether that optimization is effective). The point is to keep the code clear and concise throughout the development process, until the benefits of performance outweigh the induced costs of writing and maintaining the optimizations.

っ左2024-07-17 07:06:52

优化可以在不同的粒度级别上进行,从非常高的级别到非常低的级别:

  1. 从良好的架构、松散耦合、模块化等开始。

  2. 为问题选择正确的数据结构和算法。

  3. 优化内存,尝试在缓存中容纳更多代码/数据。 内存子系统比 CPU 慢 10 到 100 倍,如果将数据分页到磁盘,则速度会慢 1000 到 10,000 倍。 与优化单个指令相比,对内存消耗保持谨慎更有可能带来重大收益。

  4. 在每个函数中,适当使用流程控制语句。 (将不可变表达式移出循环体。将最常见的值放在 switch/case 等中)

  5. 在每个语句中,使用产生正确结果的最有效的表达式。 (乘法与移位等)

对是否使用除法表达式或移位表达式进行挑剔不一定是过早优化。 如果您没有首先优化架构、数据结构、算法、内存占用和流控制,那么这样做还为时过早。

当然,如果您没有定义目标性能阈值,任何优化都是不成熟的。

在大多数情况下,要么:

A) 您可以通过执行高级优化来达到目标​​性能阈值,因此无需摆弄表达式。

B)即使在执行所有可能的优化之后,您也不会达到目标性能阈值,并且低级优化不会在性能上产生足够的差异来证明可读性损失是合理的。

根据我的经验,大多数优化问题都可以在架构/设计或数据结构/算法级别解决。 通常(尽管并非总是)需要优化内存占用。 但很少需要优化流量控制和流量控制。 表达逻辑。 在那些确实有必要的情况下,这很少是足够的。

Optimization can happen at different levels of granularity, from very high-level to very low-level:

  1. Start with a good architecture, loose coupling, modularity, etc.

  2. Choose the right data structures and algorithms for the problem.

  3. Optimize for memory, trying to fit more code/data in the cache. The memory subsystem is 10 to 100 times slower than the CPU, and if your data gets paged to disk, it's 1000 to 10,000 times slower. Being cautious about memory consumption is more likely to provide major gains than optimizing individual instructions.

  4. Within each function, make appropriate use of flow-control statements. (Move immutable expressions outside of the loop body. Put the most common value first in a switch/case, etc.)

  5. Within each statement, use the most efficient expressions yielding the correct result. (Multiply vs. shift, etc)

Nit-picking about whether to use a divide expression or a shift expression isn't necessarily premature optimization. It's only premature if you do so without first optimizing the architecture, data structures, algorithms, memory footprint, and flow-control.

And of course, any optimization is premature if you don't define a goal performance threshold.

In most cases, either:

A) You can reach the goal performance threshold by performing high-level optimizations, so it's not necessary to fiddle with the expressions.

or

B) Even after performing all possible optimizations, you won't meet your goal performance threshold, and the low-level optimizations don't make enough difference in performance to justify the loss of readability.

In my experience, most optimization problems can be solved at either the architecture/design or data-structure/algorithm level. Optimizing for memory footprint is often (though not always) called for. But it's rarely necessary to optimize the flow control & expression logic. And in those cases where it actually is necessary, it's rarely sufficient.

(り薆情海2024-07-17 07:06:52

我尝试仅在确认性能问题时进行优化。

我对过早优化的定义是“在未知性能问题的代码上浪费精力”。 绝对有优化的时间和地点。 然而,诀窍是仅在对应用程序性能重要且额外成本超过性能损失的情况下才花费额外成本。

在编写代码(或数据库查询)时,我努力编写“高效”代码(即以最简单的合理逻辑快速完整地执行其预期功能的代码。)请注意,“高效”代码不一定与“优​​化”相同代码。 优化通常会给代码带来额外的复杂性,从而增加代码的开发和维护成本。

我的建议:当您可以量化收益时,尝试只支付优化成本。

I try to only optimise when a performance issue is confirmed.

My definition of premature optimisation is 'effort wasted on code that is not known to be a performance problem.' There is most definitely a time and place for optimisation. However, the trick is to spend the extra cost only where it counts to the performance of the application and where the additional cost outweighs the performance hit.

When writing code (or a DB query) I strive to write 'efficient' code (i.e. code that performs its intended function, quickly and completely with simplest logic reasonable.) Note that 'efficient' code is not necessarily the same as 'optimised' code. Optimisations often introduce additional complexity into code which increases both the development and maintenance cost of that code.

My advice: Try to only pay the cost of optimisation when you can quantify the benefit.

一紙繁鸢2024-07-17 07:06:52

编程时,许多参数至关重要。 其中包括:

  • 可读性
  • 可维护性
  • 复杂性
  • 稳健性
  • 正确性
  • 性能
  • 开发时间

优化(追求性能)通常以牺牲其他参数为代价,并且必须与这些方面的“损失”进行平衡。

当您可以选择性能良好的知名算法时,预先“优化”的成本通常是可以接受的。

When programming, a number of parameters are vital. Among these are:

  • Readability
  • Maintainability
  • Complexity
  • Robustness
  • Correctness
  • Performance
  • Development time

Optimisation (going for performance) often comes at the expense of other parameters, and must be balanced against the "loss" in these areas.

When you have the option of choosing well-known algorithms that perform well, the cost of "optimising" up-front is often acceptable.

離人涙2024-07-17 07:06:52

诺曼的回答非常好。 不知何故,你经常会做一些“过早的优化”,这实际上是最佳实践,因为众所周知,不这样做是完全低效的。

例如,要添加到 Norman 的列表中:

  • 在 Java(或 C# 等)中使用 StringBuilder 连接而不是 String + String(在循环中);
  • 避免在 C 中像这样循环: for (i = 0; i < strlen(str); i++) (因为这里的 strlen 是一个每次循环都会调用字符串的函数调用);
  • 看来在大多数 JavaScript 实现中,使用 for (i = 0 l = str.length; i < l; i++) 的速度更快,而且仍然可读,所以没问题。

等等。 但这种微观优化决不应该以牺牲代码的可读性为代价。

Norman's answer is excellent. Somehow, you routinely do some "premature optimization" which are, actually, best practices, because doing otherwise is known to be totally inefficient.

For example, to add to Norman's list:

  • Using StringBuilder concatenation in Java (or C#, etc.) instead of String + String (in a loop);
  • Avoiding to loop in C like: for (i = 0; i < strlen(str); i++) (because strlen here is a function call walking the string each time, called on each loop);
  • It seems in most JavaScript implementations, it is faster to do too for (i = 0 l = str.length; i < l; i++) and it is still readable, so OK.

And so on. But such micro-optimizations should never come at the cost of readability of code.

鱼窥荷2024-07-17 07:06:52

仅在极端情况下才需要使用分析器。 项目工程师应该了解性能瓶颈在哪里。

我认为“过早优化”是非常主观的。

如果我正在编写一些代码并且我知道我应该使用哈希表,那么我就会这样做。 我不会以某种有缺陷的方式实现它,然后等待一个月或一年后有人遇到问题时收到错误报告。

重新设计比从一开始就以明显的方式优化设计成本更高。

显然,第一次时会错过一些小事情,但这些很少是关键的设计决策。

因此:在我看来,不优化设计本身就是一种代码味道。

The need to use a profiler should be left for extreme cases. The engineers of the project should be aware of where performance bottlenecks are.

I think "premature optimisation" is incredibly subjective.

If I am writing some code and I know that I should be using a Hashtable then I will do that. I won't implement it in some flawed way and then wait for the bug report to arrive a month or a year later when somebody is having a problem with it.

Redesign is more costly than optimising a design in obvious ways from the start.

Obviously some small things will be missed the first time around but these are rarely key design decisions.

Therefore: NOT optimising a design is IMO a code smell in and of itself.

站稳脚跟2024-07-17 07:06:52

值得注意的是,Knuth 的原始引用来自他撰写的一篇论文,该论文提倡在精心选择和测量的区域中使用 goto 作为消除热点的一种方法。 他的引用是他添加的一个警告,以证明他使用 goto 来加速这些关键循环的理由。

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

并继续:

当今许多软件工程师所共有的传统智慧
呼吁忽视小规模的效率; 但我相信这是
只是对他们所看到的滥用行为的过度反应
精明大愚的程序员,他们无法调试或维护
他们的“优化”程序。 在已建立的工程学科中
12% 的改进很容易获得,但绝不被认为是微不足道的; 和我
相信同样的观点应该在软件工程中盛行。 的
当然我不会费心在一次性工作中进行这样的优化,
但当涉及到准备高质量节目时,我不想
将自己限制在那些无法提高效率的工具上 [即 goto
在这方面的声明]。

请记住他如何在引号中使用“优化”(该软件实际上可能并不高效)。 另请注意,他不仅批评这些“小事聪明,大事愚蠢”的程序员,而且还批评那些建议您应该始终忽略效率低下的人。 最后,说一下经常被引用的部分:

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

...然后更多地了解分析工具的重要性:

对事物的哪些部分做出先验判断通常是错误的
计划确实至关重要,因为普遍的经验
一直在使用测量工具的程序员一直认为他们的
直觉的猜测失败了。 使用这些工具七年之后,
我已经确信从现在开始编写的所有编译器都应该是
旨在为所有程序员提供反馈,表明什么
他们的部分项目成本最高; 确实,这个反馈
除非特别指定,否则应自动提供
已关闭。

人们到处滥用他的引言,当他的整篇论文都在提倡微优化时,人们常常暗示微优化还为时过早! 他批评的一群人响应了这种“传统智慧”,因为他总是忽视小细节的效率,他们经常滥用他的引言,这句话最初是针对那些不鼓励一切形式的微观优化的人的。 。

然而,这句话有利于由经验丰富的手持分析器的人使用时适当应用微优化。 今天的类比可能是这样的,“人们不应该盲目地优化他们的软件,但是自定义内存分配器在关键领域应用以改善引用局部性时可以产生巨大的差异,”或者,“使用 SoA 代表手写的 SIMD 代码确实很难维护,您不应该到处使用它,但是当由经验丰富且受指导的人员正确应用时,它可以更快地消耗内存。

任何时候,当您尝试像 Knuth 上面所提倡的那样,推广仔细应用的微优化时,最好添加一个免责声明,以阻止新手过于兴奋并盲目尝试优化,例如重写整个软件以使用<代码>转到。 这部分就是他正在做的事情。 他的引言实际上是一个重要免责声明的一部分,就像有人骑摩托车跳过燃烧的火坑可能会添加一个免责声明,即业余爱好者不应该在家尝试这个,同时批评那些在没有适当知识和设备的情况下尝试并受伤的人。

他认为“过早的优化”是那些实际上不知道自己在做什么的人所应用的优化:不知道优化是否真的需要,没有使用适当的工具进行测量,也许不了解优化的本质他们的编译器或计算机体系结构,最重要的是,是“小事聪明,大事愚蠢”,这意味着他们通过试图省钱而忽视了优化(节省数百万美元)的巨大机会,并且在创建他们无法做到的代码时更有效地调试和维护。

如果您不属于“小事聪明,大事愚蠢”类别,那么您就不会根据 Knuth 的标准过早地进行优化,即使您使用 goto 来加速关键循环(这对于当今的优化器来说不太可能有多大帮助,但如果它确实如此,并且在真正的关键区域,那么您就不会过早地优化)。 如果你真的将你正在做的事情应用到真正需要的领域,并且他们真正从中受益,那么在高德纳眼中你就做得很好。

It's worth noting that Knuth's original quote came from a paper he wrote promoting the use of goto in carefully selected and measured areas as a way to eliminate hotspots. His quote was a caveat he added to justify his rationale for using goto in order to speed up those critical loops.

[...] again, this is a noticeable saving in the overall running speed,
if, say, the average value of n is about 20, and if the search routine
is performed about a million or so times in the program. Such loop
optimizations [using gotos] are not difficult to learn and, as I have
said, they are appropriate in just a small part of a program, yet they
often yield substantial savings. [...]

And continues:

The conventional wisdom shared by many of today's software engineers
calls for ignoring efficiency in the small; but I believe this is
simply an overreaction to the abuses they see being practiced by
pennywise-and-pound-foolish programmers, who can't debug or maintain
their "optimized" programs. In established engineering disciplines a
12% improvement, easily obtained, is never considered marginal; and I
believe the same viewpoint should prevail in software engineering. Of
course I wouldn't bother making such optimizations on a oneshot job,
but when it's a question of preparing quality programs, I don't want
to restrict myself to tools that deny me such efficiencies [i.e., goto
statements in this context].

Keep in mind how he used "optimized" in quotes (the software probably isn't actually efficient). Also note how he isn't just criticizing these "pennywise-and-pound-foolish" programmers, but also the people who react by suggesting you should always ignore small inefficiencies. Finally, to the frequently-quoted part:

There is no doubt that the grail of efficiency leads to abuse.
Programmers waste enormous amounts of time thinking about, or worrying
about, the speed of noncritical parts of their programs, and these
attempts at efficiency actually have a strong negative impact when
debugging and maintenance are considered. We should forgot about small
efficiencies, say 97% of the time; premature optimization is the root
of all evil.

... and then some more about the importance of profiling tools:

It is often a mistake to make a priori judgments about what parts of a
program are really critical, since the universal experience of
programmers who have been using measurement tools has been that their
intuitive guesses fail. After working with such tools for seven years,
I've become convinced that all compilers written from now on should be
designed to provide all programmers with feedback indicating what
parts of their programs are costing the most; indeed, this feedback
should be supplied automatically unless it has been specifically
turned off.

People have misused his quote all over the place, often suggesting that micro-optimizations are premature when his entire paper was advocating micro-optimizations! One of the groups of people he was criticizing who echo this "conventional wisdom" as he put of always ignoring efficiencies in the small are often misusing his quote which was originally directed, in part, against such types who discourage all forms of micro-optimization.

Yet it was a quote in favor of appropriately applied micro-optimizations when used by an experienced hand holding a profiler. Today's analogical equivalent might be like, "People shouldn't be taking blind stabs at optimizing their software, but custom memory allocators can make a huge difference when applied in key areas to improve locality of reference," or, "Handwritten SIMD code using an SoA rep is really hard to maintain and you shouldn't be using it all over the place, but it can consume memory much faster when applied appropriately by an experienced and guided hand."

Any time you're trying to promote carefully-applied micro-optimizations as Knuth promoted above, it's good to throw in a disclaimer to discourage novices from getting too excited and blindly taking stabs at optimization, like rewriting their entire software to use goto. That's in part what he was doing. His quote was effectively a part of a big disclaimer, just like someone doing a motorcycle jump over a flaming fire pit might add a disclaimer that amateurs shouldn't try this at home while simultaneously criticizing those who try without proper knowledge and equipment and get hurt.

What he deemed "premature optimizations" were optimizations applied by people who effectively didn't know what they were doing: didn't know if the optimization was really needed, didn't measure with proper tools, maybe didn't understand the nature of their compiler or computer architecture, and most of all, were "pennywise-and-pound-foolish", meaning they overlooked the big opportunities to optimize (save millions of dollars) by trying to pinch pennies, and all while creating code they can no longer effectively debug and maintain.

If you don't fit in the "pennywise-and-pound-foolish" category, then you aren't prematurely optimizing by Knuth's standards, even if you're using a goto in order to speed up a critical loop (something which is unlikely to help much against today's optimizers, but if it did, and in a genuinely critical area, then you wouldn't be prematurely optimizing). If you're actually applying whatever you're doing in areas that are genuinely needed and they genuinely benefit from it, then you're doing just great in the eyes of Knuth.

西瓜2024-07-17 07:06:52

对我来说,过早优化意味着在你拥有一个可以工作的系统之前,在你实际分析它并知道瓶颈在哪里之前,尝试提高代码的效率。 即使在那之后,在许多情况下,可读性和可维护性也应该优先于优化。

Premature optimization to me means trying to improve the efficiency of your code before you have a working system, and before you have actually profiled it and know where the bottleneck is. Even after that, readability and maintainability should come before optimization in many cases.

一笔一画续写前缘2024-07-17 07:06:52

我不认为公认的最佳实践是不成熟的优化。 更重要的是要在“假设”上浪费时间,这些假设是潜在的性能问题,具体取决于使用场景。 一个很好的例子:如果您花了一周的时间尝试优化一个对象的反射,然后才证明它是一个瓶颈,那么您就过早地优化了。

I don't think that recognized best practices are premature optimizations. It's more about burning time on the what ifs that are potential performance problems depending on the usage scenarios. A good example: If you burn a week trying to optimize reflecting over an object before you have proof that it is a bottleneck you are prematurely optimizing.

放血2024-07-17 07:06:52

除非您发现由于用户或业务需求而需要应用程序具有更高的性能,否则没有理由担心优化。 即使如此,在分析完代码之前也不要执行任何操作。 然后攻击花费最多时间的部分。

Unless you find that you need more performance out of your application, due to either a user or business need, there's little reason to worry about optimizing. Even then, don't do anything until you've profiled your code. Then attack the parts which take the most time.

萌能量女王2024-07-17 07:06:52

正如我在类似问题上发布的,优化规则是:

1) 不要优化

2)(仅适用于专家)稍后优化

什么时候优化过早? 通常。

例外情况可能出现在您的设计中,或者出现在大量使用的封装良好的代码中。 过去,我曾研究过一些时间关键的代码(RSA 实现),其中查看编译器生成的汇编器并删除内部循环中的单个不必要的指令,从而获得了 30% 的加速。 但是,使用更复杂的算法所带来的加速比这要高出几个数量级。

优化时要问自己的另一个问题是“我在这里所做的相当于对 300 波特率调制解调器进行优化吗?”。 换句话说,摩尔定律很快就会使你的优化变得无关紧要。 许多扩展问题可以通过投入更多硬件来解决。

最后但并非最不重要的一点是,在程序运行速度太慢之前进行优化还为时过早。 如果您正在谈论的是 Web 应用程序,您可以在负载下运行它以查看瓶颈在哪里 - 但您很可能会遇到与大多数其他站点相同的扩展问题,并且将应用相同的解决方案。

编辑:顺便说一句,关于链接的文章,我会对所做的许多假设提出质疑。 首先,摩尔定律在 20 世纪 90 年代不再发挥作用的说法并不正确。 其次,用户的时间比程序员的时间更有价值这一点并不明显。 无论如何,大多数用户(至少可以这么说)不会疯狂地使用每个可用的 CPU 周期,他们可能正在等待网络执行某些操作。 另外,当程序员的时间从实现其他事情上转移到在用户打电话时程序执行的事情上减少几毫秒时,就会产生机会成本。 任何比这更长的时间通常都不是优化,而是错误修复。

As I posted on a similar question, the rules of optimisation are:

1) Don't optimise

2) (for experts only) Optimise later

When is optimisation premature? Usually.

The exception is perhaps in your design, or in well encapsulated code that is heavily used. In the past I've worked on some time critical code (an RSA implementation) where looking at the assembler that the compiler produced and removing a single unnecessary instruction in an inner loop gave a 30% speedup. But, the speedup from using more sophisticated algorithms was orders of magnitude more than that.

Another question to ask yourself when optimising is "am I doing the equivalent of optimising for a 300 baud modem here?". In other words, will Moore's law make your optimisation irrelevant before too long. Many problems of scaling can be solved just by throwing more hardware at the problem.

Last but not least it's premature to optimise before the program is going too slowly. If it's web application you're talking about, you can run it under load to see where the bottlenecks are - but the likelihood is that you will have the same scaling problems as most other sites, and the same solutions will apply.

edit: Incidentally, regarding the linked article, I would question many of the assumptions made. Firstly it's not true that Moore's law stopped working in the 90s. Secondly, it's not obvious that user's time is more valuable than programmer's time. Most users are (to say the least) not frantically using every CPU cycle available anyhow, they are probably waiting for the network to do something. Plus there is an opportunity cost when programmer's time is diverted from implementing something else, to shaving a few milliseconds off something that the program does while the user is on the phone. Anything longer than that isn't usually optimisation, it's bug fixing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文