如何避免“开发人员的不良优化直觉”?


22

我在一篇发表以下声明的文章上看到:

开发人员喜欢合理地优化代码。它是如此令人满意和有趣。但是,知道何时进行优化更为重要。不幸的是,开发人员通常对应用程序中的性能问题的实际位置有着可怕的直觉。

开发人员如何避免这种直觉?是否有好的工具来查找您的代码的哪些部分真正需要优化(对于Java)?您是否知道有关该主题的一些文章,技巧或精彩读物?


1
这归结为“在做出决定时如何避免[依靠]直觉?” 简单:您可以通过事实和数据进行验证。因此,在优化的情况下,从开发人员的角度来看:您进行基准测试。
haylem 2011年

Answers:


44
  • 使用好的分析器来识别昂贵的方法。
  • 记录热点实际花费的时间。
  • 编写热点的更快实施
  • 记录热点现在需要多长时间,希望不再使它们成为热点。

本质上,您需要能够向其他人证明问题出在哪里,并且这种改变使它消失了。

我个人认为,由于无法证明有所改进,因此可以立即回滚到原始版本。


51
或更简单地说:“为了避免不良的优化直觉,请不要使用直觉。要进行度量。”
Kyralessa

6
这就是为什么您的回答是答案,而我的只是评论。:P
Kyralessa

2
@Thomas,如果您摆弄可读性和可维护性,那么您并不是在关注性能问题,对吗?

3
@托马斯,我不同意。即使在规范范围内,您也需要彻底重新测试新代码。旧代码不需要这样做。还原。

2
@Thorbjørn性能调整之后,您还需要彻底重新测试新代码。如果引入了缺陷,则节省时间或内存毫无意义。
Thomas Owens

10

知道在哪里进行优化的唯一方法是分析代码。确保知道性能最差的代码在哪里,然后从那里开始,而不是进行您认为会带来好处的更改。

Java通过VisualVM工具使此过程非常容易,该工具已与Java开发工具包(JDK)的最新版本捆绑在一起。这样做的目的是找出代码中和外部库中最常使用的方法,以及花费最多时间使用的方法。您还可以获取有关垃圾收集的性能数据,以便调整收集器并调整应用程序所需的最小/最大堆空间。


VisualVM不在JRE中,仅在JDK中。

1
@ThorbjørnRavn Andersen很好。我应该澄清。但是,如果您正在进行Java开发,则通常会安装JDK(尽管您可能正在运行OpenJDK或类似的文件-我不知道VisualVM是否附带了这些文件)。
Thomas Owens

1
我经常在Eclipse中切换工作区,然后将其默认为启动Eclipse的JRE。由于安装JRE比JDK容易得多,因此我们已慢慢迁移到包含Eclipse编译器的ant构建过程,因此可以在纯JRE上运行。因此,你这几天可以真正做实事,而不JDK。VisualVM可以单独下载,从而可以更轻松地与给定的Java versino一起使用,因为在Windows 64位JVM下无法连接到32位JVM,反之亦然。

9

当这里的任何人都在谈论探查器时,我将重点讨论问题的这一部分。

开发人员如何避免这种直觉?

您。做。不。相反,您永远不会尽早优化
一遍又一遍,重复一遍,因为这是一种宗教口头禅。

您会发现自己正在这样做,并且会发现自己不应该这样做。
然后再说一次。
然后再次。

早期优化是程序员的主要罪行之一

工具和物料是后来的优化的一部分,这是一种既定的工艺


可以肯定的是,早期的“卷积代码”优化。选择适合您的问题并(具有预期的处理负载)具有良好性能特征的算法和/或数据结构是开始编写代码之前应做的事情。
Vatine 2012年

@Vatine是的,去过那里。不,只是不要。做适合您眼前问题的思维导图的事情。它可能性能最高的算法,但我希望您不必这样做。
ZJR 2012年

在我看来,这是YAGNI的原则-您将不再需要它!
EL尤苏波夫2012年

7

这些工具称为探查器。您可以使用它们来实际衡量程序中哪个部分需要最多的时间来执行,从而可以将精力集中在哪里。

同样重要的是在更改再次进行测量,以确认您的更改具有预期的效果。


5

还要查看程序使用了多少内存,而不仅仅是速度或运行时。

许多使用Java之类的垃圾收集语言的编码人员都误以为垃圾收集可以防止内存泄漏。事实并非如此。如果您拥有对不再需要的对象的引用,则该对象将不会被收集,因此会泄漏。

我已经看到Java Web应用程序泄漏太多,以至于它们的服务器将无法使用交换空间!

如果同时使用运行时分析器和某种形式的内存分析器,您将学习直观地编写更快,更精简的代码。这样的结果是您的代码在第一次尝试时更有可能快速运行。


1

我的补救措施是从获得两个问题的明确答案开始:

  1. 如何衡量性能(例如衡量数据加载时间
  2. 目标值是多少(例如,在3秒或更短的时间内以95%的置信度加载数据

从曾经受邀保存我们产品的最新版本的老虎团队成员那里学到了上述技巧。该发行版由于性能原因而被破坏,这可能会使公司失去战略客户,这有力地证明了人的参与(顺便说一句昂贵)。我被派去协助他们澄清项目细节;还以此为契机,学习了一两次关于性能的知识。


1

我发现过早优化的最佳解药就是这种方法

一旦使用它来加速某些代码(如本例中所示),它就会成瘾,并且您了解性能调整的首要原理不是调整代码,而是找到问题所在

真正的优化是过早的优化,因为狩猎养家糊口就是射击锡罐。这全都与寻找采石场有关。


1
不幸的是,您只能背负200磅的重物回家,所以不要整天射击松鼠。
约旦

1

旧问题,但我将提供与其他答案有很大不同的答案。

提高性能的巨大机会来自并行处理。 尝试设计代码以利用多个线程。(即使为简单起见,即使在版本1中也没有这样做)。几乎不需要猜测或直觉。

其他任何事情都是过早的优化,需要您的直觉,这通常是错误的。


真的很好。过去,您可以指望处理器每隔几年就会变得越来越快。现在,您只应该期望会有更多的处理器。
JimmyJames

0

您的直觉随着时间而改善。我可能会提出一些争议,但是在使用VTune和CodeAnalyst以及现在使用CodeXL的多年中,我想我的直觉要比以前准确得多,至少可以确定热点的位置当我分析一些代码时,我不再完全措手不及。这并不意味着我会尝试盲目优化。

分析实际上增加了我对探查器的依赖性,但并没有减少。我只是说我可以更轻松地预测分析结果在某种程度上是什么,此外,可以成功消除热点并缩短完成用户端操作所需的时间,而不会在黑暗和丢失中蒙上阴影甚至在使用探查器时也可以执行此操作,直到您不仅开始了解热点是什么,而且相对于缓存未命中,为什么确切地知道它们是热点)。

但是,直到我开始使用探查器后,我才开始改善这种直觉。原因之一是因为,如果您熟悉代码,就最大,最明显的热点而言,您的预感可能是正确的,但两者之间的所有细微之处都不正确。自然,如果您有一个需要花费一个小时才能完成的用户端操作,并且有一个庞大的二次复杂度算法可以处理跨越十万个元素的输入,那么您可能会冒充您的整个生命,将其视为二次复杂度算法在这里出错。但这并不能为您提供任何详细的见解,或者说,您确切地知道是什么对时间没有帮助。

当您开始进行概要分析并查看所有您认为可能对时间造成较大影响的事情并没有花费太多时间时,您将拥有太多价值。并不是显而易见的低效率来源,而是您怀疑的那些效率低下的东西,但是经过分析后,意识到它们几乎在任何时候都没有做出贡献。这可能是您获得最直观的洞察力的地方,就是发现自己在所有细微的地方都表现出错误,这些地方并不清楚确切花费了多少时间。

超出明显算法复杂性的人类直觉通常会以错误的方式开始,因为对机器有效的与对人脑有效的有很大不同。首先,考虑从寄存器到CPU缓存再到DRAM到磁盘的内存层次结构并不是那么直观。并非凭直觉就认为冗余算术可能比对查询表进行更多分支或内存访问来跳过某些处理工作要快。我们倾向于从打折的角度来考虑要做的工作,而这些工作需要减少决策成本,内存加载和存储等成本。对于硬件而言,高效的方法通常会违反直觉,这会破坏您一开始的所有人类假设,

通过配置文件改善界面的直觉可以帮助界面设计。事后更改界面设计的成本非常高昂,取决于该界面的位置,成本与位置数量成比例地增加。当您开始改善直觉时,您可以在第一时间更好地设计界面,从而为将来的优化留出喘息的空间,而无需进行昂贵的设计更改。再说一次,这种直觉是您通常会开发的东西,并且通过始终使用该分析器可以无限期地继续发展。


0

探查器有助于解决代码方面的错误直觉。鉴于当今有多少硬件预测,预测代码的性能并不现实,但在几十年前的Knuth时代,这仍然是正确的,他主张将探查器作为开发标准工具的一部分,以解决该问题。开发人员的“一分钱一斤的愚蠢”性质。但是考虑到答案在其他方面的综合程度,我将走一条截然不同的路线,并说用户端的理解是另一个“解决办法”。

根据我的亲身经历,我亲眼目睹了一位特别出色的开发人员(但是对于用户实际使用软件的方式存在盲目的盲点),使用分析器优化了细分算法(一种非常好,昂贵且全面的方法:带调用图的Intel VTune当细分简单的图元(例如具有6个笼/输入多边形的多维数据集)时,网格物体在GPU剖析器顶部进行采样)可在GPU上以数十亿个面实现惊人的结果。除了他针对那个测试用例进行了调优以外,这与任何实际用例都不一样(用户不希望十亿个小面到一个细分的立方体开始像一个完美的球面,他们的细分输入往往是角色和车辆之类的东西。和其他复杂的输入)。

有趣的是,我的大脑只有他一半的功能,而且在我的职业生涯中没有博士学位,这仅仅是因为我了解用户想要什么,市场想要什么,设计师想要什么。我不能真正强调足够的用处,以使自己置身于用户的心态和底下,并查看您的软件以及它作为实际用户所需要做的事,同时努力使自己与您付出的努力分离开来。来构建您所构建的内容,并用新的眼睛看着它。我什至在开发人员之上遇到过,这是一件不可能的事情。他以为我对所有技术精通但对用户无视的开发人员都拥有类似的自负感,并且当用户和设计师蜂拥而至地谈论我该怎么做时,我不断证明他是错的。这听上去很自负,但我会在免责声明中说:我不是一个出色的编码器,但我确实了解用户和设计师的需求,这使我在我的领域特别受青睐,因为这在我看来尤其罕见质量出于某种原因。作为程序员,我们可能更习惯于进行测试,而不是与普通的非技术人员进行了解和社交。

因此,这里需要进行概要分析和适当地度量,但实际上也需要确保您使用真实用户实际将要提供给应用程序的输入类型来度量操作。否则,您甚至可能手头仍然有VTune或CodeAnalyst或gprof或任何其他探查器,同时尝试针对开发人员看似正常的测试用例,但对用户而言却晦涩难懂的地方来优化热点,最终导致对通用用例感到悲观为了支持一些晦涩的用例,很少有用户(如果有的话)曾经考虑申请。

归根结底,我们往往会承担所有不切实际的事情,因为开发人员可以与铁锤相提并论,这些铁锤可以使用户真正地感到足够快乐,而无需解决世界饥饿问题,以及赚钱的实际需要,以便我们可以支付租金或购买啤酒或看看裸女或您想要/需要做的任何事情。所有其他一切都可能与基本业务需求相抵触,任何如此高尚,如此英勇的开发人员都忘记了这与赚钱并最终使用户满意以使他们付钱有关,这可能会使自己扎根并关闭“上帝”模式,创建支持真实世界的虚拟世界,只需运送并获得一些食物即可。我们可能会迷失在软件指标和实践中,但从根本上讲,

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.