您应该在什么时候开始考虑性能?


16

在构建应用程序时,我发现自己不断在问这是否是执行或实现某些功能的最佳方法。通常,我会在stackoverflow或其他论坛上发布问题,仅希望收到反馈,以便收到有关如何不“把马放到马前”有关性能的评论。大多数程序员在应用程序完成之前是否真的没有考虑性能,还是性能绝对不能接受?我的意思是,我了解开发环境与生产环境不同,您不应该完全依赖开发笔记本电脑的结果...但是,有些实践和技术可以提供比其他产品更好的性能。

在整个开发过程中考虑性能是不好的做法吗?在性能真正下降之前,我应该推迟考虑这些因素吗?

更新资料

明确地说,我是在谈论您正在考虑或即将使用某些功能的情况。您知道有几种实现方法,但是您不确定每个实现的扩展程度。另外,可能还有几种您不熟悉的技术。在较小的规模上,任何一种方法都可能是适当的,但是在较大的规模上,某些方法会跟上,有些则不会。通常,当我征求意见或指导时,答复是:以后再担心...


我尽量不要写那些胡扯的胡扯。我从不在乎启动代码中这条清晰明了的行是否比耗费大量精力的“优化”版本花费更多的CPU周期。您在谈论哪种“性能思考”?

达阿林,不是很明显吗?当你等待你的试镜!
马特·艾伦

Answers:


24

推迟考虑性能有时是基于以下短语的错误使用:

过早的优化是万恶之源。

如果您阅读完整的引文,则Knuth试图说的是,在开发过程中不进行概要分析而进行的微优化通常是不可取的,因为它们导致可维护性较低的代码,而未必会带来实质的性能优势。

但这并不意味着您不应该在应用程序即将完成之前考虑性能。如果这样做,您可能会发现性能不足,您的设计架构不支持更好的性能,因此您必须重新开始。

在开发过程中,无需深奥的(和过早的)优化,您可以做很多事情以达到良好的性能:

  1. 使用明智的,经过深思熟虑的架构。
  2. 正确使用数据结构。
  3. 使用性能适当的技术(库,框架)。

如果您做这些事情,您会发现任何需要进行的性能优化都将局限于代码的一小部分。分析将识别该代码,并允许您将性能改进的重点放在最能发挥其作用的地方,而不会牺牲可维护性。


5
+1用于以一种可行的方式照亮伟大贤哲的友善但过度使用的词组。我知道太多的程序员可能还会将该短语缝到工作站上的采样器中,因为他们每天都使用它作为在编写解决方案之前不花任何力气想出一个好的解决方案的理由。
亚当·克罗斯兰

@Adam-谢谢!我完全同意!我个人不理解为什么您不希望在编写大量代码之前就花时间去思考。
Cognitronic 2011年

+1为三分。完成后,它们都被钉在系统上,并在性能优化上进行了大量工作。如果一切都完成,您将无法获得增加。也不能完全同意亚当的观点,有些人将引号用作放松的盾牌。
Zekta Chan 2011年

20

以下是不需考虑的内容:

  • ++ii++
  • switchif
  • 我是不是该 inline职能吗?
  • 虚拟功能慢吗?
  • C ++ / Java / C#是否比另一个更快/更慢?
  • 等等等等

这是要考虑的事情:

  • 实际的预期工作量是多少?
  • 输入信息多久更改一次,由谁提供?考虑进行预编译是否有意义?
  • 我是否保持数据结构尽可能简单和规范化?这意味着不必担心哈希和类似的东西。
  • 我是否将通知数量保持在最低限度?(在那儿,数据的一部分需要同时进行另一部分的同时更改,因为数据结构没有被规范化。)

关于后一点,以我的经验,最好设计数据结构,以便在必须进行非规范化的情况下能够容忍暂时的不一致,以后可以通过某种定期扫描来解决。性能的主要杀手是当通知触发更多的通知时,这些通知会进一步触发,从而达到您从未想过的程度。通常,由于自我取消的变化,这是浪费的精力。

如果完成所有这些操作,那么您将获得一个干净的设计。然后在开发时定期进行配置。(我所依赖的方法是“ 随机暂停 ”。)然后,如果您看到通过引入更复杂的算法可以提高性能,则一定可以这样做。


2
好的答案;太糟糕了,问题很快就解决了CW,否则您可能会获得一些代表。编辑历史中曾经有一个审核记录,以显示发生的时间以及原因。现在看来,SE网络正在秘密执行此操作。
罗伯特·哈维

@罗伯特:是的。伤心。我只需要在我的虚拟啤酒中哭泣即可:-)
Mike Dunlavey

3

不,您不应该从一开始就考虑性能(尤其是在设计数据库中)。认为任何优化都是过早优化的人们对我们的行业造成了很多伤害。该报价原本是为了防止人们在问题发生之前先进行微观优化。完全不打算进行任何优化。例如,在数据库中,有许多已知的技术表现不佳。在设计中,避免这些是您需要做的一部分。重构具有1亿条记录的数据库非常困难,因为它是使用性能不佳的技术设计的,我们再也无法通过购买更好的硬件来避免此问题。


3

担心正确性1,然后再维修,那么安全性和可靠性,然后你可以考虑一下性能。在开发过程中,将此顺序应用于每段代码。高效的解决方案很可能会自然而然地失去保持简单明了的效果。

80%的性能是针对当前问题选择正确的算法和数据结构;在一般情况下(最坏的情况是平局),最差优化的快速排序仍然无法击败高度优化的气泡排序。

SO上的每个人都试图打消“更快,++ p或p ++”的心态,在这种心态下,人们过于精于编译器,以至于他们无法追踪更大的问题,从而导致代码脆弱,易错缠身,错误和最重要的是,这没有比一个更直接的解决方案要快的多。我已经直接处理了这类代码。一个例子是如此的脆弱,以至于我们如果不彻底破坏它就无法做出任何改变。


1 “正确性”是指“符合规格”,与“无错误”同义。


1
一些规范定义了性能要求,这会对您的订单产生什么影响?
本L

@Ben:理想上没有。但是,如果满足上述要求,但仍不能满足硬性能要求,则第一步是进行概要分析以找到瓶颈(duh)。在那之后,这是一个判断电话。您牺牲可维护性,安全性或可靠性吗?我想不出一刀切的解决方案。我对安全性和可靠性更为偏执,因此我可能会优先考虑可读性,但可能是运行时环境本身足够安全和​​稳定,可以交易其他两个环境。
约翰·博德

2

一旦知道什么是“好”性能,就应该开始考虑性能。换句话说,在确定以下阈值是什么之前开始考虑性能是错误的:

  • 令人无法接受的性能-立即修复
  • 可接受的性能-在尝试对性能进行更多处理之前,是时候专注于其他功能了。
  • 目标绩效-理想的绩效数字。即,如果您有足够的时间和资源,您将需要系统做什么?

确定了这些阈值后,还确定了用于衡量性能的指标。这意味着您可以设置一些可以每天运行几次的自动化性能测试。它将告诉您您是好还是坏。

要提出这些指标,您需要了解系统需要做什么。例如,是要求绝对性能指标(在X时间内响应)还是在吞吐量测量中(每Y时间X响应)?吞吐量和绝对时间优化需要不同的方法,如果您不知道真正重要的是什么,则可能是错误的方法。


1

您可能已经听说过早的优化是万恶之源。问题是什么使它为时过早?在我看来,考虑性能从来不是一个坏主意,但是在您的代码起作用之前,请不要过分担心。一旦可行,请进行一些重负载测试,分析并确定瓶颈,并进行性能优化。

话虽这么说,但是如果您知道某些可以带来真正改变的技术,那么在初始编码阶段就无需考虑性能问题。例如,从库中选择一种存储结构,而不是从另一种结构中选择,因为过去的经验告诉您,其中一种存储结构比另一种存储结构更快/使用的内存更少。否则构建一个简单的对象为您知道的数据(如果需要以后的测试,可以使其更复杂)缓存系统将被大量访问,并且缓存会更好。这样,您就不会为性能感到烦恼(至少最初不是这样),而是使用从其他项目中学到的技巧和窍门。尝试使这些内容保持简单,以便在初始开发中轻松添加它们,并可能也会带来一些好处。


1

性能应在需求文档的系统和用户相关规范中进行详细说明。我知道很多人都在嘲笑在应用程序开发中进行需求分析的想法,但是令人惊讶的是,这样的文档将简洁地回答在应用程序接近完成时应将性能相关资源用于什么以及在何处投入。并且它将及时回答该问题

需求文档将为您节省数百小时的时间,否则将浪费在不必要的流程上。


1

平衡的方法会更好。性能很重要,但不像完成任务那么重要,因此:

  1. 首先构建一个功能,尝试对自己的工作方式和方式做些思考(花一点时间考虑性能,但不要过多)
  2. 测试一下
  3. 一旦开始运行,就开始考虑是否确实有必要进行改进(通常不会,但是有时可能会)。

这是我执行性能与功能的常用方法,在一般情况下,这全都取决于程序的工作并验证是否有必要使事情更好地工作以及花费多少时间。

让我们考虑这样一个问答网站,我想它背后的人肯定会思考如何提出问题并尽可能多地获得回答。但是,在考虑通知时,通知是否偶尔出现并告诉您有新的答案或其他内容实际上并不重要。


1

安全考虑性能的一种方法是:尽可能使用领域特定的语言。

如果您的大部分开发工作都可以通过自己的小DSL完成,并且设计得足够好,可以以最通用和最高级的形式表达您的问题域,那么就可以首先获得有效的原型,而无需考虑性能,然后仅改善DSL实施,而不改善实际的问题域代码。

从可维护性的角度来看,这也是一种更好的方法。


1

您应该考虑性能。但是,由于(通常)您的时间比计算机的时间重要,因此您必须划出一条线来标记调整的结束。

关于性能的一篇非常好的文字文章是:Computer Performance Shell Game

计算机性能Shell游戏(也称为“发现瓶颈”)始终在以下四个资源之间进行播放:

  • 中央处理器
  • 磁碟
  • 网络
  • 记忆

在任何给定的时刻,您的计算机都在等待对这些资源之一进行某些操作。但是,哪一个是CPU,内存,磁盘或网络?如果您对性能感兴趣,那么绝对要做的第一件事就是确定当前哪些瓶颈正在阻碍性能-并消除它。


0

“最佳”方式是一个非常繁琐的术语,答案可能高度取决于直到运行时才知道的因素。

  • 你有足够的记忆力吗?-使用“全内存”数据结构可以获得更好的性能,但是如果没有足够的内存交换,则会降低性能。
  • 您需要坚持吗?数据库具有完整性,但是比上面的“全内存”数据结构慢。 MUCH慢。
  • 您可以缓存结果吗?清漆可以帮助您! http://www.varnish-cache.org/

这个清单不胜枚举。

你有什么可以做的,是写从知识,你目前“能够工作的最简单的事情” 拥有的,做一个模块化的方式,所以当你知道更多,你可以很容易地重新组织。请注意,“最简单”的东西不一定简单!


0

您始终应该牢记这一点。我认为大多数人都想说的是,花两天时间来优化您甚至都不知道的东西已经损坏是没有意义的。产品投入运行并可以进行一些可用性测试后,应该可以向您显示性能问题所在。然后,一旦您确定了真正的性能问题,就可以针对需要执行的优化。


0

至少从理论上讲,您应该在Beta测试之后而不是之前就开始考虑性能。

但是,这不是做出不良设计决策的许可。例如,使用NVARCHAR字符串作为主键是确保性能下降的必经之路。也就是说,不管性能问题如何,这都是一个肮脏的习惯,您不应该一开始就使用它。

如果您的设计遵循传统的最佳做法(所有第3范式,正确的信息隐藏在您的类中,对单例的使用最少等),并且以后出现性能问题,那么它将很容易处理(在此处创建索引,在那里实现缓存)。

高温超导


0

这取决于。记住80/20规则很有用:应用程序中的大多数代码(例如80%)永远不会执行得足够频繁,以至于不会在性能上产生任何显着差异。您需要关注剩余的20%,其中应用程序必定要花费其执行时间的80%左右。

您可能能够提前确定一些明显的性能热点,例如,如果您知道特定的计算将被重复数百万次。在这种情况下,绝对值得考虑的是通过选择正确的数据结构和算法来对其进行优化。

但是,这种优化更多是设计活动。通常没有用的是微观优化,因为有人用“获得性能”的名义花了过多的时间进行巧妙的位摆弄技巧。尤其是如果前后没有进行适当的测量,此类更改可能不会产生任何影响,或者在现实生活中会减慢应用程序的运行速度。


0

这取决于您所处的发展阶段

1)如果您要构建软件的功能,请继续进行并确保其正常运行(即,期望且有效)。

2)一旦集成了构建基块,您将获得资源消耗的提示,还有优化的空间。


0

如果您必须开始考虑性能,那就麻烦了。您应该一直在考虑性能。实际上,我怀疑优秀的程序员会以“男人每隔七秒钟就考虑一次性”的方式去考虑性能,即使他们不打算这样做。

重要的是,您将根据所有这些想法采取何种行动。想法很便宜,但是行动会破坏代码并延误期限。

在大多数情况下,唯一明智的行动就是什么也不做:您发现自己的代码不会被频繁调用以至于无法观察到性能问题,也许这是一段启动代码,对于每台计算机而言,您潜在用户群的1%,也许是一小部分冗余服务器代码被缓慢的数据库访问淹没了,也许这只是代码的非关键部分中的整数分配。

通常,您怀疑给定的操作可能会导致性能问题,可以通过简单的更改来解决。例如,有些the的感觉是,对每个请求运行复杂的SQL查询,或者两次从字典中请求相同的数据片段,这对您不利。这是使用优化技术知识的地方,也许最令人惊讶的结论发生了:

如果您知道一种几乎可以肯定会提高一段代码性能的快速技术,请不要这样做。

如果您现在可以考虑一下,那么肯定可以在五分钟后完成。将其保留在代码之外(但可以在// TODO注释中保留)可以使代码更整洁,并节省您以前的时间来使用其他功能,而如果您最终以后将该代码扔掉,则不会浪费时间。如果原始代码在测试时确实导致性能问题,请返回并应用快速技术。

我并不是在这里说您应该避免编写惯用的代码,因为它恰好更快。根据最佳实践编写惯用代码,以提高生产率和可读性并减少错误。只是,如果您在惯用的按书编写的代码和更快但更容易编写的替代方法之间进行选择,请始终追求可读性而不是速度。

唯一的困难情况是,似乎没有简单的方法可以提高代码性能,但是很痛苦的是,一段代码一旦交付就将被破坏—每次单击都会遍历完整的数据库,一百个SQL请求网站上的每页,或类似的可怕内容。这是您实际需要停下来思考的地方。这些通常是架构问题,无论如何都无法在本地解决。迅速提出建议或原型,以确认您的怀疑,寻找相似的经验和常见的解决方案,并考虑更改体系结构或删除某些功能。


0

恕我直言,在实施系统之前考虑性能非常重要,但只能考虑一下。您应该分析该应用程序,并找出可能是潜在的性能瓶颈。

然后,尽可能简单地实施该系统。如果出现性能问题,请进行优化。

例如,假设您有一个GUI客户端,它通过某种服务(SOAP,REST HTTP等)获取数据。那么,对于高性能/可伸缩性来说,最重要的事情就是要有尽可能少的呼叫,让每个呼叫返回大量数据,而不是让许多呼叫每个都返回少量信息,即,喜欢粗俗的通信而不是闲聊。

在实现这种系统时,我不会在乎系统之间的调用数量。但是,我将确保代码库将使我在需要时可以轻松地进行重构/优化。


0

您应该从一开始就以非常一般的方式考虑性能。您应该选择适合您的应用程序并合理有效的数据结构和算法。算法对于软件至关重要,而数据结构则更为重要。如果您需要对其中之一进行重大更改,则可能需要进行重大重写,而较小的细节可以更容易地重写。

您可能还想养成高效的习惯,但这取决于语言。例如,在C ++中,“ ++ i;” 作为独立的语句或表达式始终至少与“ i ++;”一样好,并且可能效率更高。但是,在大多数情况下,您应该编写清晰的代码并信任编译器。养成担心微效率的习惯几乎肯定会给您带来比解决的问题更多的问题。对于桌面应用程序,无论是对于i >> 1vs而言i / 2,编译器至少与您一样聪明,或者提高性能的最佳方法是获得更好的编译器,因此不必担心。

除此之外,在拥有可以测试的内容之前,请不要担心。那时,您可以对程序进行概要分析,以查看热点位置,并可能了解是否有性能程序。如果您需要提高性能,请找到程序大部分时间都花在哪里,然后在那里进行改进。如果您设计时具有足够的全局效率,并且编写了不错的程序,那么您只需要更改程序的一小部分即可。


0

我认为您可以做的最好的事情就是遵循良好的设计规范(例如,不要做一些您知道会妨碍性能的事情),直到您能够正常工作。如果无法衡量改善,就无法改善。一旦有了可以测试的东西,那么进行概要分析并了解热点(如果有)的位置通常是个好主意。如果有什么意外的事情发生,您应该考虑重构或重写问题区域,但是如果情况还不错的话(只是因为代码将其90%的时间花在了两种或三种方法上,如果总体性能令人满意,这并不意味着什么)然后继续发展。我已经不止一次地看到开发人员花了几天时间来优化系统中最复杂的部分,


0

我什么时候应该开始考虑呢?我应该付出多少努力?这取决于项目的Cockburn规模。(换句话说,没有良好表现的风险是什么?)

提前了解基础知识(请参阅Robert Harvey的答案)。为了在软件开发的各个阶段应用面向性能的思想,开发人员必须从内而外地了解它,这样,思考过程就不会受到那些额外考虑因素的阻碍。(换句话说,在构想项目之前就开始考虑性能。)

在开发的早期阶段,请自由使用性能分析工具并跟踪统计数据的历史记录。在组织此类信息时要特别注意,以使其对以后的决策有用。

然后,根据项目的性质及其Cockburn规模:

  • 快速原型开发,或“像没有明天一样发布代码”,或对业务影响很小的内部开发:只需保留统计数据即可。暂时不要考虑性能。以最简单的方式实现功能。坚持您想到的第一个算法。

    • 在项目的后半部分,将进行临时性能测试,以根据实际用例确定“热点”。如果存在任何导致软件无法使用的性能问题,则应易于识别。
    • 对于业务影响较小的内部开发,只需部署代码并稍后解决性能问题。
  • 桌面应用程序,需要一致,全面的性能方法。不必进行高度优化。但是,应尽可能减少“挂起”(无响应)。

    • 桌面应用程序通常具有高度复杂的执行路径,这会使面向性能的思考变得复杂。分层设计将使数据库/网络性能问题与GUI性能问题分开,由团队中的不同专家来处理。
    • 日志跟踪的历史记录将允许识别热点。
  • 高性能计算,这需要充分利用硬件的性能。

    • 任命您团队中的某人负责分析和报告绩效统计信息。
    • 建立有关性能特征的理论,通过实验进行验证,并与简化的Comp Sci模型中的预测进行比较。
    • *

0

一开始。确定所需的性能特征。如果无法确定目标,则需要退后一步以更好地了解您的要求,或者推迟到知道组件要求并可能要重写的风险之后再进行。然后,进行测试。不要优化,测试。如果您的代码未通过性能测试,请进行优化。有了适当的测试框架,使用现有的性能监视工具将使该任务相当容易。

在项目的整个生命周期中,都应进行性能测试,以作为回归测试。维护代码因触发性能问题而臭名昭著,因为“修补程序”通常只关注很窄的范围。


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.