我父亲是一位退休的程序员,我给他看了答案。他绝对确定,即使是程序员,即使在微观水平上也没有考虑其性能,他们也不是优秀的程序员。
我不太确定-也许计算能力的提高意味着我们不再需要考虑这种微观性能的改进?也许这种考虑取决于编写实际语言代码的人? (在上述情况下为PHP)。
环境因素可能很重要-互联网消耗了世界10%的能源。我想知道在数百万个网站上进行数万亿次复制时,浪费几微秒的代码是多么浪费吗? />微优化在编码时重要吗?
我个人对25个答案的总结,谢谢大家。在非常罕见的情况下。在大多数情况下,可靠性和可读性更为重要。但是,不时考虑进行微优化并没有什么坏处。基本的理解可以帮助我们在进行诸如
if (expensiveFunction() || counter < X)
之类的编码时,不要做出明显的错误选择。应该是
if (counter < X || expensiveFunction())
/>(来自@ zidarsk8的示例)这可能是一个便宜的函数,因此更改代码将是微优化。但是,有了基本的了解,您就不必这样做了,因为您一开始就可以正确地编写它。
#1 楼
我既同意也不同意你的父亲。应该尽早考虑性能,但只有在您真正知道在CPU绑定的小型代码段中花费大量时间的时候,才应该早考虑微优化。微观优化通常是在没有任何程序实际花费不必要的时间的概念的情况下完成的。该程序没有明显的效率低下,它通过一系列诊断和加速步骤进行操作,直到比开始时快43倍。问题会。如果您执行诊断(在我的情况下是随机暂停),则优先暴露相当一部分时间的代码行。如果您查看这些内容,可能会找到替代代码,从而将总体时间减少了大约那一部分。总体时间已减少,这些事情现在所占比例较大,因此,如果再次执行所有操作,则也可以消除该比例。如果您在多个迭代中继续执行此操作,那么就可以不必进行任何微优化就可以实现大规模的加速。经过这种经验,当您遇到新的编程问题时,您就会认识到最初导致这种低效率的设计方法。以我的经验,它来自数据结构的过度设计,非规范化的数据结构,对通知的大量依赖等。
#2 楼
微优化只有在数字表明正确的情况下才是重要的。如果性能对客户或用户来说都是一个问题,那么针对您所开发的需求应该有一些性能数据规范。在开发软件时,应根据这些要求测试系统的性能。如果不满足性能要求,则需要分析代码库并根据需要进行优化以达到性能要求。一旦达到所需的最低性能,就无需从系统中榨取更多性能,尤其是如果您要再损害代码的可读性和可维护性时(根据我的经验,高度优化的代码可读性较低,可维护的,但并非总是如此)。如果可以在不降低系统其他质量属性的情况下获得额外的性能提升,则可以考虑使用。
在某些情况下,性能至关重要。我主要考虑实时系统和嵌入式系统。在实时系统中,更改操作顺序可能会对满足正确操作所需的严格期限产生巨大影响,甚至可能影响计算结果。在嵌入式系统中,您通常具有有限的内存,CPU电源和电源(如电池电源),因此您需要减小二进制文件的大小并减少计算量,以最大化系统寿命。
评论
另一方面,如果在使用较慢功能与较快功能之间存在问题,则没有理由使用较慢功能-就像在isset的情况下一样。
–马夫里克
11年8月8日在17:32
@Mavrik是的。如果您有X和Y这两个函数,并且Y的速度比X快(至少在您的特定条件下),那么即使代码仍具有可读性和可维护性,也没有理由不使用Y。但是,如果您不了解Y,并且需要重构代码以使用Y而不是X,并且(该代码段的)性能不是问题,则没有理由进行更改。权衡取舍–性能,时间,成本,工作量,可读性/可维护性等。
–托马斯·欧文斯♦
11年8月8日在17:37
我全心全意地同意,在微优化方面我只是想指出这一点-如果在可读性/时间方面不花任何钱,那就去做吧。否则不要。
–马夫里克
11年8月8日在18:52
+1高度优化的代码可读性和可维护性较低,但并非总是如此。
–博兹
2011年8月9日在7:51
在其他情况下,表现很重要:(1)游戏; (2)海量数据; (3)高流量网站; (4)高度复杂的UI的响应能力; (5)应该在后台运行的服务,例如病毒检查; (六)财务; (7)智能手机;等等。它几乎不限于RTS和嵌入式系统等神秘案例。
–雷克斯·克尔(Rex Kerr)
2011年8月9日在20:36
#3 楼
每当有人问到优化问题时,我都会想起Michael A. Jackson的报价。程序优化的第一条规则:不要这样做。仅供专家使用!):尚未这样做。 * 8')
第二条规则的隐含之处是分析您的代码,只花时间优化会有所作为的事情。
在汇编时,您父亲的主张是正确的。但这比当今大多数人编写的程序更接近金属。如今,即使尝试优化自己(不进行概要分析)也可能导致代码运行速度比采用更通用的方法慢,因为现代JIT编译器很可能会优化该通用方法。
在C中,您必须非常擅长优化,才能比编译器更了解如何优化代码段。程序员应该了解内存,那么即使尝试优化自己,您也可能会失败。但是,与论文标题相反(实际上是对大卫·戈德堡的同等奇妙的敬意,“每个计算机科学家应了解的浮点运算”),没有这样的理解并不一定会阻止您成为一名优秀的程序员,只是另一种程序员。
isset()
与PHP中的strlen()
我不了解PHP,所以
isset()
的用途确实不明显。我可以从上下文中推断出它,但这意味着它对PHP初学者来说同样是晦涩难懂的,甚至可能会使更有经验的程序员倍受关注。这是一种惯用的语言,会使维护成为一场噩梦。不仅如此,而且不能保证
isset()
总是会更高效,因为现在它会更高效。现在,优化可能不是明年或十年内的优化。 CPU,系统,编译器会随着时间的推移而不断改进和变化。如果PHP的strlen()
的性能有问题,PHP可能会在将来进行修改,则可能需要删除所有isset()优化以再次优化代码。每次优化都有可能成为未来的反优化,因此应被认为是可能的代码味道,应将其保持在最低水平。巨大的代码库充满了形式为
if x==0 z=0 else z=x*y
的代码,因为有人假设浮点乘法总是比分支更昂贵。在最初的目标体系结构上,这种优化使代码的运行速度提高了一个数量级,但时间却在变化。语句导致管道刷新。将所有这些代码行简化为z=x*y
,使得该程序在新架构上的运行速度提高了一个数量级,从而恢复了因反优化而损失的性能。到20甚至10年前我们必须进行优化的时间。 CPU级别,但是随着我们转向多进程和多处理器体系结构,锁和进程间通信变得越来越重要。 Drepper的论文确实可以帮助理解许多这些问题。评论
您要避免管道刷新和高速缓存未命中:D它们的成本太高了。但是仅在执行它们的许多部分上。
–deadalnix
11年8月8日在17:33
我要补充的一件事是,编译器已经走了很长一段路,并将为您优化很多东西。 AFAIK,它们比棘手的东西更好地优化了清晰易读的代码。
–嗡嗡声
2011年8月8日在18:43
+1提供了一个浪费时间的微优化的真实例子,并揭示了迈克尔·杰克逊是一名程序员。
–博兹
2011年8月9日在7:54
+1例如。它完美地说明了为什么您应该将琐碎的转换留给编译器。
–back2dos
2011年8月9日在8:13
@Rex Kerr>例如,代价来自分支,这会导致CPU的管道刷新。浮点乘法也很昂贵。更高级的取决于FPU和运行代码的CPU的管道长度。我不感到惊讶的是,该代码在较旧的CPU上运行速度更快,而这些CPU的流水线较短且FPU效率不如当前CPU。
–deadalnix
2011年8月10日23:22
#4 楼
编写干净,简洁,简单且易于解释的代码。
进行性能测试以识别瓶颈。
优化关键部分。
thumb:95%的代码在5%的时间内运行。在对代码进行概要分析/基准测试并查看有95%的时间运行的5%之前,没有必要进行优化。
每个白痴都可以进行微优化,任何体面的编译器/运行时都可以为您做到这一点。编写优化的代码,然后尝试使其达到最佳状态,充其量是乏味的,而最糟糕的情况是不可持续的。找到瓶颈,并使用C扩展重写它们。甚至超出混淆点的范围内对PHP代码进行微优化也不会获得几乎相同的速度。因为很明显。因为它会很快奖励您。因为您不必做出重要的决定。这是拖延的完美手段。它使您可以逃避软件开发的真正重要部分:可扩展,灵活,可扩展,健壮的系统的设计。
评论
在《 Bugzilla开发人员指南》中,可以找到对我最好的答案:“如果您试图变得聪明而不是可读性,那么也许您是想使事情“更快”? :不要在知道问题存在之前就解决问题,如果您(通过实际的详细测试)不知道自己的代码运行缓慢,则不必担心使其变得“更快”。优化-许多程序员正在不断解决没有人遇到过的问题。不要那样做。” bugzilla.org/docs/developer.html#general
–马可
2011年8月9日在9:45
我通常都同意-除了一条观点,我认为“每个白痴都认为他们可以进行微优化” ...;)
– Nim
2011年8月9日14:24
@Nim:点;)
–back2dos
2011年8月9日15:59
#5 楼
我会同意你父亲的看法:“如果一个程序员即使在微观水平上也没有考虑其代码的性能,那么他们就不是好程序员。”关键是“考虑性能”。这不等同于“在每一步都进行微优化”。我同意其他大多数意见-用来使C程序更快的功能可能在今天还不行-但是还需要考虑其他重要事项:我应该使用C还是C ++?如果您经常使用带有简单重载运算符的类,则它们可能会降低性能。有关系吗这取决于您的应用程序,但是即使您不考虑它,您也不是一个非常好的程序员。有些人可能会考虑它大约2毫秒然后将其关闭,但我认为太多字面上甚至根本没有考虑它。代码将花费更长的时间来编写。代码的速度会快一点到一个数量级之间(这是罕见的)。您的客户可能不知道它们之间的区别。
另一个现实是人们喜欢重用代码,代码的最终位置可能与编写代码时完全不同。突然之间,人们可能会在意。
举个例子,假设您在PC或游戏机上写了《愤怒的小鸟》之类的东西。您无视物理系统和图形系统中的优化-因为这些天以来最低要求是2.5 GHz双核,并且您的游戏运行良好。然后,智能手机问世,您想移植它。哦,该死的600 MHz ARM内核?
想想一个网站-在周末像“热”还是“不”之类的东西混在一起。您可以使用任何方便的数据库,在考虑到快速发展的情况下编写所有内容,并通过向您的朋友发送URL发送电子邮件。三个月后,您的服务器因过载而濒临崩溃,无法采取任何措施来扩大规模。它一直在发生。最大的网站上的电费单以数百千瓦甚至兆瓦为单位。考虑一下,通过代码优化可以节省兆瓦。
就像您父亲说的那样,您至少必须考虑一下。大多数人甚至都不知道桌面上有多少性能,并以“过早的优化”和“不做”的快速技巧来掩饰它。这些不是优秀的程序员。
这在这些站点上并不受欢迎。再见声望点....
评论
当然,您应该考虑一下它(在脑后),并且通常会拒绝它,除非证明它值得。您需要考虑的是,优化通常会降低代码的可读性,并且可能会使编码和维护所需的时间增加10倍左右。如果程序不占用大量CPU,则通常不需要。认识到您的编译器通常在优化方面比您要好得多,并且许多优化实际上会损害性能。如果不值得花时间测试您的优化和配置文件,那么就不值得花时间进行优化。
– jimbob博士
2011年8月8日在20:34
您的《愤怒的小鸟》示例准确地说明了为什么您不应该过早地进行优化。从台式机到控制台再到移动设备的移植中,您正在(至少)处理三种截然不同的硬件,对一种硬件的优化可能会损害而不是对另一种硬件有所帮助。更糟糕的是,优化会使代码更难于理解,因此难以移植。当然,从一开始就选择高效的算法,但是当实际数据会告诉您每个平台的问题出在哪里时,可以在性能调整阶段保留微优化。
–卡莱布
2011年8月9日14:50
@Caleb:《愤怒的小鸟》示例确实说明了为什么不针对特定硬件进行优化。它还说明了如何构建整个应用程序而无需费心进行更常规的“ C级别”优化,然后就不知所措。实际上并没有被烧毁,但是有超出原始意图的麻烦。
– phkahler
2011年8月9日18:06
#6 楼
让我们先来看一下您的情况:PHP我不认为PHP是一种语言(由于其性质和应用程序的主要领域),您无需担心“微观优化”。 PHP代码大部分是通过操作码缓存进行优化的。您必须将优化代码插入C扩展,然后动态加载到PHP运行时中。
因此,您可以看到,通过对PHP代码进行微优化,我们没有动力。花时间让PHP代码更具可读性和可维护性-这将为您带来更多的收益。我的代码使用诸如Python或Ruby之类的动态语言-因为它们不是为CPU密集型数字运算任务而设计的。他们解决了不同类别的问题,在这些问题中,以精细的方式(易于阅读和维护)对现实世界进行建模(称为表达性)比速度更为重要。如果速度是最主要的考虑因素,那么它们根本就不会动态变化。但同样,首先,您必须查看所编写程序的性质/领域/用途。您还应该仔细权衡微优化的时间与该优化的收益。如果您需要更多的优化,那么不妨考虑下一个步骤-并在汇编器中对这些代码进行编码。优化在编码时重要吗?” -答案是-它取决于-
您正在做什么:应用程序域,复杂性?
微秒级的速度提高对您的程序来说真的很重要吗? ?
哪种优化最有益?它可能不一定总是代码优化,而是外部的。通过其他方式-通过更改硬件,RAM和处理器,并行执行代码或在分布式系统上执行代码?扭曲了代码的自然可读性,从而使维护工作量大。始终认为这是万不得已的方法-始终尝试采用比优化单个代码文件更好的硬件和更好的体系结构来优化整个应用程序。
#7 楼
似乎有很多答案说微观优化是所有关于权衡的方面-性能,时间,成本,工作量,可读性/可维护性等。但是我知道有些优化不会影响可读性,我只是想做些有趣的事情。我在一些学校作业(全部基于速度)中看到,编写条件语句时考虑微优化总是很不错的事情,例如:
比
if (counter < X && shouldDoThis()) // shouldDoThis() is an expensive function
有很多方法可以像这样“加速”您的代码,并且差异通常可以忽略不计(虽然并非总是如此),但是如果我就是这样写的。
评论
对于此特定情况,这可能并不重要。但是,我认为能够识别这样的优化非常重要,这样,当它变得很重要时,您就不必花费不必要的时间来分析和优化。
– tskuzzy
2011年8月9日17:01
这是一个非常危险的例子。优化绝不能改变行为。甚至暗示Cheap()&&昂贵()是昂贵()的优化&&便宜()邀请人们盲目地用一个替换另一个,而无需考虑它所造成的重大语义变化(在&&是短路运算符的语言中)。
– Mark Booth
2011年8月11日10:23
如果这些功能没有副作用,则它们是等效的,并且更快。如果它们确实有副作用,则不应一开始就这样编写代码。我什至会说这是出于习惯而应该做的-除非它实际上改变了行为。
– phkahler
2012年2月14日在16:59
@MarkBooth我必须在这里同意phkahler,这些功能都没有副作用! if语句中condionos的顺序必须不影响程序的结果。我的示例最好写成好像(x <100 && isPrime(x)),只是为了使其更加清晰。
– Zidarsk8
2012年2月16日在22:02
@ zidarsk8-如果优化更改了执行速度以外的任何其他内容,则不是优化。作为程序员,我们通常必须务实,有时这意味着我们不能保证与短路操作符一起使用的所有函数都是纯函数-尤其是当我们的代码调用无法控制的第三方库时。在这种情况下,您必须注意不要鼓励没有经验的程序员以优化的名义引入错误。
– Mark Booth
2012年2月19日在22:33
#8 楼
在我职业生涯的早期,诸如“不要进行微优化”之类的笼统声明引起了很多混乱。一切都是偶然的。因此,人们说“最佳实践”而不是“做到这一点”的原因。考虑到所有情况,“最佳实践”是最佳选择。例如,应使用LINQ和Entity Framework代替内联SQL。在我公司,我们使用SQL Server2000。SQLServer 2000不支持实体框架。最佳做法要求:
让我的老板考虑购买新版本的SQL Server的想法,这意味着几千美元。
向开发人员介绍学习新技术的想法。
我从经验中知道这不会发生。因此,我可以辞职,无休止地坚持下去,或者不遵循最佳实践。
决策背后存在着政治,技术和金钱方面的考虑,影响了总体结果。做出决定时请记住这一事实,并明智地选择自己的战斗。
评论
顺便说一句,您可以将Dapper用作嵌入式SQL的微型ORM替代品。
–丹
2011年8月8日17:13
应该使用LINQ和Entity Framework代替内联SQL -直到您真正需要内联SQL来优化某些内容为止; EF产生的SQL并非总是最佳的。
–罗伯特·哈维(Robert Harvey)
2011年8月8日在17:52
再次,如果您的老板担心SQL 2k8的许可费用(或其他任何现行费用),则应指出它已经足够老,可以很快上线EOL(如果还没有的话)
–沃伦
11年8月8日在18:19
@warren-有些公司没有考虑到此类问题。对于某些人来说,如果它仍然“起作用”,则它们将不会升级。通过工作,我的意思是服务器仍在运行。我们已经看到EF缺乏支持。仅仅说服他们花钱根本不够。
–P.Brian.Mackey
2011年8月8日在18:44
众所周知,您可以将EF与SQL 2000一起使用。设计器不起作用,但是实际的实体框架确实支持SQL2000。要解决设计器的局限性,您可以使用相同的架构在sql 2008 express中创建本地数据库作为sql 2000数据库,请设计人员将其指向生成所有类,然后进入.edmx文件,并将目标数据库版本更改为2000,并将连接字符串指向sql server 2000数据库。不是最好的解决方案,但是如果您不能升级,它就可以工作。
–尼尔
2011年8月8日在21:52
#9 楼
这始终是一个折衷。首先,计算机产业的发展最终关乎金钱。作为开发人员,您需要做的是为客户创造价值,以便您赚钱(这是过分简化,但要点在此处)。机器动力也要花钱。通常,第二个成本要比第一个成本低得多。因此,拥有可读性和可维护性的代码是资本,因此开发人员可以将大部分时间花费在交付价值上。但是它们通常涉及可读性较低的代码或扩展性较小的代码(这不是链接示例的情况,但总的来说是这样)。这将花费开发人员的时间。这次比机器动力更昂贵,这是浪费。
第二,大型项目中的微优化会使维护/发展变得越来越难。这样做的问题是,在进化时,现在可能无法进行其他优化。随着应用程序的不断发展,通常您最终会得到比没有进行这些优化的解决方案要慢的解决方案。第三,优化通常是毫无意义的,因为算法复杂度通常可以克服如果数据集增加,您可能会进行微优化。令人遗憾的是,由于微优化使您的代码难以维护/发展,因此这些优化可能更难进行。或飞机的自动驾驶仪)。但这必须得到证明。通常,您的程序大部分时间都花在有限的代码中。无论您进行哪种微优化,都无法在不发现瓶颈的情况下并在此部分上进行工作,从而使程序的任何有价值的工作都变得更快。如您所问,您的问题表明您没有在实际程序中对该问题进行基准测试。在这种情况下,您可能会成功,并注意到它是否更快。所以您在有任何问题之前先问过这个问题。这就是问题所在。您正以错误的方式处理优化问题。
由于维护和演进通常比微优化更有价值,因此在执行任何操作之前,请确保具有正确的接口。然后,如果程序的各个部分彼此足够抽象,则可以对一个部分进行微优化,而不会弄乱整个过程。这要求您的界面运行足够长的时间才能被信任。
评论
“总会有一个权衡”。的确,如果程序处于折衷曲线上,则减少一个变量将增加另一个变量。以我的经验,大多数程序都离折衷曲线不远,并且有足够的空间来减少这两个变量。
–迈克·邓拉维(Mike Dunlavey)
11年8月8日在18:03
+1维护和改进比微优化更有价值。尽管我确信计算机行业的意义远不只是金钱?例如,开源,教育,创新,治理,社区等。我敢肯定,金钱可以找到它的根源,但这在大多数情况下都是如此。
–博兹
2011年8月9日在8:08
@Boz kay>这部分是正确的。首先,因为您的老板和客户大多对那些事一无所知,并且对钱不感兴趣。如果要推广某些开源工具,则必须告诉他们如何改善公司品牌或如何降低开发成本。另外,使开发人员满意是在公司中获得优秀开发人员的一种方法。优秀的开发者可以赚钱(主要是投入质量和创新)。最后,金钱是关键。我在linux计算机上写了一个很棒的免费软件支持者。教育也是如此。
–deadalnix
2011年8月9日,12:19
#10 楼
性能是功能杰夫·阿特伍德(Jeff Atwood)的文章是建立高性能网站的出色文章,并且这样做的重要性...进行微优化,直到需要为止。您可以执行更多具有成本效益的优化。专注于体系结构,而不是代码。我看到的大多数执行缓慢的网站都存在高级问题(不必要的Web服务层,不良的数据库设计,过于复杂的体系结构),这些问题不仅会对性能产生不利影响,而且根深蒂固且难以修复。
建立网站时,客户端代码和数据库逻辑比服务器端代码更容易引起性能问题。就像其他任何东西一样,如果您会遇到性能问题,甚至可以更好地分析代码,便可以尽早找到它们。
#11 楼
开发人员时间比计算机时间花费更多。通常这就是您要优化的内容。但是:微优化和算法复杂度之间是有区别的。花足够的时间来确保您使用的算法正确。
确保您问的是正确的问题,
select (select count(*) from foo) >= 1
与select exists(select 1 from foo)
不同。 某些语言习惯用法之所以流行是因为它们速度更快。可以使用它们,因为大多数流利的语言用户都会熟悉它们。 (您的示例就是一个很好的示例)。
#12 楼
您想优化什么?软件性能如何?
可靠性吗?
程序员的生产力?
客户满意吗?
电源效率?
可维护性?
上市时间?
成本?
“优化”并不总是意味着使代码的运行速度与可能。有时候找到绝对最快的方法来完成某件事很重要,但这实际上并不是大多数代码中都常见的。如果用户没有注意到50到100微秒之间的差异,那么实际上仅在偶尔运行的代码中两者之间没有任何差异。这是一个示例:
如果您需要不断更新显示用户输入的长度以及两个例程确定该长度远小于两次输入之间的时间所花费的时间连续两次击键,实际上使用哪个例程都没关系。另一方面,如果您需要确定十亿个字符串的长度,则可能需要密切注意不同例程之间的性能差异。在第一种情况下,您可能希望编写易于理解和验证的代码。在第二种情况下,您可能愿意以可读性为代价。如今的程序非常复杂,以至于通常很难分辨出瓶颈在哪里。概要分析可以帮助您优化正确的代码,然后证明您所做的优化确实有效。
您没有说父亲何时退休或他做了什么样的编程,但是他的反应不足为奇。从历史上看,内存,辅助存储和计算时间都很昂贵,有时甚至非常昂贵。这些天,与程序员的时间相比,所有这些东西变得非常便宜。同时,处理器和编译器已经能够以程序员无法匹敌的方式优化代码。程序员使用小技巧在这里烧掉一些机器指令的时代已经荡然无存。
评论
+1更不用说在过去的几年中,移动设备再次高度依赖代码优化。没有编写优化代码或至少认为没有优化代码的人可能很难让他们的CPU密集型应用程序在移动设备上平稳运行。
–Styler
11年8月8日在20:42
+1非常类似于您的可能优化列表。他使用了assembly / fortran
–博兹
2011年8月9日在8:14
@Styler:很快,直到移动设备具有带GB内存的四核CPU,我们已经有了双核智能手机。
– Lie Ryan
2011年8月9日23:37
@Lie Ryan:是的,这是事实,但是像大多数开拓者一样,他们不得不乘木船旅行;)
–Styler
2011年8月10日13:41
#13 楼
在编写代码时进行微优化并不重要。优化应该在探查器的帮助下完成,在需要的地方优化代码。但是,程序员在编写代码时应尽量避免做明显的愚蠢的事情。
例如,不要在循环内重复执行昂贵的操作。将值存储在循环外的变量中并使用它。不要在经常调用的函数中一遍又一遍地执行字符串比较或正则表达式之类的事情,当您可以上一层级时,进行比较并将其变成整数,函数引用或派生类。
经验丰富的程序员可以轻松记住这些内容,并且几乎总是可以提高代码质量。
评论
意识到我需要在问题编辑中清楚一点,我实际上是在说同样的话-我已对其进行了更新。
–博兹
2011年8月10日在17:08
#14 楼
在决定优化方法时,请始终记住阿姆达尔定律。请参阅链接以获取精确的数学信息;要记住的精妙声明是:如果程序的一部分占其运行时间的10%,并且将该部分优化为运行速度的两倍,则整个程序只能将速度提高5%。这就是为什么人们总是说不值得优化程序中不占总运行时间百分之几的部分。但这只是更一般性原则的特例。阿姆达尔定律告诉您,如果您需要使整个程序的运行速度快两倍,则需要将每个程序的平均速度提高50%。它告诉您,如果您需要处理20 GB的数据,只有两种方法可以使读取速度比从磁盘读取20 GB的时间更快:获得更快的磁盘或减小数据容量。 />
那么,阿姆达尔定律对微观优化有何看法?它说,如果全盘适用,他们也许值得。如果您可以将程序中每个功能的运行时间节省百分之一,那么恭喜您!您已使程序加速了百分之一。那值得吗?好吧,作为一个编译器专家,我很高兴找到可以做到这一点的优化,但是如果您是手工完成的话,我会说寻找更大的东西。
评论
+1是Amdahl的报价,但我不同意“要使整个程序的运行速度快两倍,您需要加快每个程序的速度”。我会说您实际上并没有加快任何“步伐”。相反,您会发现不必要的工作并将其消除。如果程序比玩具大,则尤其是函数调用。关于性能的许多常见想法似乎完全忽略了找到调用树的整个不必要分支(可以是单个指令)并将其关闭的重要性。
–迈克·邓拉维(Mike Dunlavey)
2011年8月9日在2:38
魔鬼出现在“平均”一词中。从数学上讲,要使程序加速50%,平均每个程序段必须加快50%。现在,如果您可以将程序划分为一个占用了运行时75%的工作,而另一个占用了25%的工作,并将前一个工作的速度提高了3倍,那么尽管对后者没有做任何事情,但总体上可以使您获得50%的工作。但是更常见的情况是,有数十个“作业”占用的运行时间少于5%,然后您必须加快工作速度或摆脱其中的许多工作。
– zwol
2011年8月9日在3:30
我认为有一个更常见的情况。有一项“工作”占用了50%的时间,但是您实际上并不需要它,因此可以将其完全删除,从而将总时间减少该数量,然后重复执行。我知道这很难接受-程序可能会花费大量时间做(事后看来)完全不必要的事情。但是,这是我的规范示例。
–迈克·邓拉维(Mike Dunlavey)
2011年8月9日在12:43
#15 楼
这取决于您所处的开发阶段,最初开始编写东西时,微优化不应该被考虑,因为与使用微优化相比,使用良好的算法将获得更多的性能提升。另外,考虑一下您正在开发什么,因为对时间敏感的应用程序将比常规业务应用程序从微优化考虑中获得更多好处。如果您正在测试和扩展软件,那么微优化可能会损害您的利益。往往会使代码更难阅读,甚至会引入自己独特的,需要修复的错误集以及需要修复的其他错误。
如果您实际上收到了用户对慢速代码的抱怨那么它们可能值得考虑,但前提是必须解决所有其他问题,即:
代码编写正确吗?
可以使用更好的算法吗?
如果所有问题都已解决,而您仍然遇到性能问题,那么可能是时候开始在代码中使用微优化了可能会发生其他变化(即更好的代码,更好的算法等)比起微优化,您可以获得更多的性能提升。
#16 楼
执行速度是影响程序质量的众多因素之一。通常,速度与可读性/可维护性成反比。在几乎所有情况下,代码都必须是人类可读的,以便可以维护代码。当速度是基本要求时,唯一会损害可读性的时间。使代码比完全可读性/可维护性所允许的速度更快的要求几乎从未适用,但是在某些情况下会适用。要记住的主要事情是,微优化代码通常是hacky代码,因此,除非在某处有已定义的要求,否则解决问题几乎总是错误的方式。例如,在CRUD操作中,用户几乎永远不会注意到.5秒和1秒执行时间之间的差异,因此您无需进入Assembly-interop-hackfest即可达到0.5秒。是的,我可以驾驶直升飞机上班,它的飞行速度是它的10倍,但我并不是因为价格高和直升飞机很难飞行这一事实。当您不必要地对代码进行微优化时,这正是您正在做的事情:增加不必要的复杂性和成本以达到多余的目标。#17 楼
当您遇到限制时,微优化很重要。您关心的是内存,吞吐量,延迟或功耗。请注意,这些是系统级的特征。您不需要(也不能)以各种方式优化每个功能。嵌入式系统更可能需要微优化,因为约束更容易受到打击。但是,即使进行微优化也只能让您走到这一步。您无法对不良设计进行微优化。在系统中进行良好设计的要点是,您可以对整个系统进行推理。需要进行微优化的组件应该以不损害系统设计的方式整齐地暴露和优化。
请注意,当今的小型“嵌入式”系统可能与Vaxen或Vaxen十分接近。过去是PDP-11,因此这些问题过去更为普遍。在执行现代通用商业计算的现代通用系统上,微优化是很少见的。
但是,无论您处理的是纳秒,毫秒,秒还是小时,都没有关系。问题是相同的。必须在系统和您要达到的目的的上下文中对它们进行评估。嵌入式系统的开源视频编码器。
#18 楼
微优化的最大问题是,它会使您编写难以维护的代码。优化”。进行许多微优化会消耗大量时间来对抗那些并不重要的事情。 ,更易于维护,并且如果遇到性能问题,可以运行配置文件以找出真正导致代码变慢的原因。而且,确切地知道什么是真正的坏处,您可以解决它。
#19 楼
如果您开始担心毫秒,则应考虑放弃PHP并改用C或Assembly。我并不是要这样做,讨论这些数字并使用脚本语言只是没有意义。这里的环境因素是毫无疑问的,那些服务器始终以24/7运行,如果它们确实处理某些事情,则仅当它确实在运行任务时才重要很长一段时间。
在我们大家键入问题和答案时,很可能是您办公室里的灯和我们的计算机所使用的能量,它比任何合理的微优化都消耗了更多的能量。应用于您的应用程序将永远保存。
评论
+1关闭指示灯或不回答问题。
–博兹
2011年8月9日7:44
#20 楼
您应该为任务选择最佳,简单的算法。它需要简单的原因是保持代码可读性。之所以需要最好的原因是为了避免以不良的运行时特性开始。当您知道自己将拥有大型数据集时,请不要盲目选择BubbleSort。不过,对于偶尔包含10个元素的情况也很好。通常以可读性为代价)。评论
当您的数据几乎只用几个离它们的最终目的地不太远的杂散元素排序时,BubbleSort实际上比Quicksort或mergesort更好。但是,对于所有其他任务,应使用编程语言为您提供的内置排序功能。这是最简单的入门方法(大多数语言中的内置排序功能具有良好的性能)。错误的建议:首先从不良的运行时特性开始,不要故意从不良的运行时特性开始。
– Lie Ryan
2011年8月10日13:50
@Lie,如果您知道数据几乎已排序并且因此可以使用Bubblesort,那么您并不是完全盲目地选择算法...也感谢您指出了错字。
–user1249
2011年8月10日14:11
#21 楼
我之前已经说过,在这里我会说:“过早的优化是万恶之源”。这应该是任何程序员的中心规则之一。在某种程度上,代码总是可以比现在更快。除非您手工组装带有特定芯片的组件,否则通过优化始终可以获得一些好处。但是,除非您想手动组装所有工作,否则就必须有一个量化的目标,一旦达到目标,您就说“就足够了”并停止优化,即使仍有明显的性能问题也是如此。面对您。
漂亮,优雅,性能极佳的代码如果不起作用的话就没用了(“工作”是指在所有预期输入的情况下产生预期输出)。因此,始终将生产有效的代码始终放在首位。在工作之后,您要评估性能,如果缺乏性能,您会寻找改善它的方法,直到达到足够好的水平为止。将影响绩效;非常基本的决定,例如您将使用哪种语言/运行时来实现此解决方案。与调用一种方法相比,其中许多方法对性能的影响要大很多数量级。老实说,PHP作为一种脚本语言,已经对性能产生了很大的影响,但是由于很少有脚本站点是使用C / C ++自下而上构建的,因此可以与您可能选择的其他技术(Java Servlets,ASP.NET)相提并论。等)。
之后,I / O消息大小是您的第二大性能杀手。即使I / O操作背后的算法高效,对硬盘,串行端口,网络管道等的读写操作通常也会将程序的运行时间缩短多个数量级。之后,降低算法本身的Big-O复杂性,然后如果绝对必要,则可以通过选择较便宜的方法调用并在低级别进行其他深奥的决定来“微优化”。
评论
+1有效的生产代码应该始终是第一要务。
–博兹
11年10月10日在2:41
@Keith,实际上是Knuth首先说的,他的意思不止于此。
–user1249
2011年8月10日下午14:12
“使它工作,然后使其按需要的速度工作”,Anon。
–约翰·桑德斯(John Saunders)
2011年8月10日19:46
宗教实际上是万恶之源,但我离题。
–托马斯·埃丁
2012年7月31日,0:04
#22 楼
您提到您的父亲是退休的程序员。在大型机领域工作的程序员必须非常关注性能。我记得在研究美国海军的一项活动时,他们的大型机硬件受限于每个用户64 KB的内存。在那个编程世界中,您必须小心自己的每一点。但是,嵌入式系统程序员仍然会这样做,并且数据库人员仍然非常需要使用优化的代码。#23 楼
编写代码时应绝对清楚其功能。然后,当且仅当它太慢时,再返回并加快速度。如果可以理解,总是可以将代码更改为以后更快的代码,但是如果运气好,也可以将其更改为清楚。#24 楼
重要的是:1)某人的生活取决于您的代码。在某人的心率监测器中执行耗时25ms的函数可能是个坏主意。
我个人采取了两种方法-您可以进行微优化,但这不会影响可读性-显然您想使用那些。但是,如果它影响可读性,请暂缓使用-您将不会获得太大收益,并且从长远来看实际上可能需要花费更长的时间进行调试。
评论
您的示例仅需注意以下几点:只要耗时25分钟,其他必需的任务就可以发生,那么心率监测器中耗时25ms的功能就不会成为问题。中断对此有好处。对于仅监视现实世界事件以更新显示器以供人类使用的事物,延迟25ms可能不是问题。
– Janm
2011年8月9日,1:11
#25 楼
在进行编码时,微优化是否重要?可能效果不佳,因为开发人员桌面上的最佳选择不一定与服务器上的相同。在这里,请看一下其中一些高级软件与硬件的距离。考虑到硬件的多样性,当新模型可能在不到一年的时间内问世时,针对特定芯片(例如CPU或GPU)优化代码的可行性如何?
这里的另一个问题考虑用以下度量标准衡量性能:执行速度,执行中使用的内存,新功能的开发速度,服务器上已编译或反编译形式的代码大小,可伸缩性,可维护性等?如果从广义上讲,这个问题就变得微不足道了,但是我不确定您打算在多大程度上采用真正的性能,只要可以通过某种方式对其进行衡量,就几乎可以做到。
有些微优化可能行之有效,有些则可能行不通,这使人们想知道,与其他工作相比,执行新工作或将其视为更高优先级(例如新功能或修复错误)的价值是多么值得。另一个问题是硬件或软件的升级是否也会破坏其中的一些优化。
评论
请注意,您绝对可以在JVM和.NET等平台上进行微优化,它们的形式略有不同。但是,如果您将旧的简单C编译器与更现代,高度优化的编译器进行比较,则同样如此:用户可以执行的优化看起来会有所不同。
–约阿希姆·绍尔(Joachim Sauer)
11年8月8日在19:40
#26 楼
我认为好的编程和微优化之间有很大的区别。使用更快。总是。这是很好的编程。没有理由不使用更好的算法来解决问题。甚至记录下来也很容易:给算法名称,每个人都可以在Google上搜索它并找到有关其工作原理的更多信息。他们会很快。他们会很小。他们将使用所需的最小内存。即使使用它们,您的程序仍然不具有这种性能,您也可以考虑对其进行微优化。而且您必须真正了解能够进行微优化的语言。
总是有空间在硬件上花费更多的钱。硬件便宜,程序员昂贵。通过优化何时可以购买硬件,不要花费太多时间/金钱。
#27 楼
IMHO代码的可读性比微优化更重要,因为在大多数情况下微优化是不值得的。有关无意义微优化的文章:
作为我们大多数人,我厌倦了阅读有关无意义的博客文章
微优化,例如用echo替换print,用$ i ++ ++++ i或用单引号将双引号引号。为什么?因为99.999999%的时间是无关紧要的。为什么?因为99.99%的时间,您最好
安装像APC这样的PHP加速器,或者在数据库列上添加这些丢失的索引,或者尝试避免有1000个数据库请求
在首页上。
print使用了另外一个操作码,因为它实际上返回了一些内容。我们
可以得出结论,回声比打印要快。但是一个操作码不会花费任何费用,
我尝试了全新的WordPress安装。该脚本在笔记本电脑上以“ Bus Error”结束之前停止
,但是
操作码的数量已超过230万。
因此,在大多数情况下,微优化可以节省数百万种操作中的1种,但使可读性变差。
#28 楼
其他答案也很对。但是,我还要补充一点,必须区分过早的优化/微优化和编写性能代码,以反映对语言/框架构造行为的理解(对不起,最后一个单词找不到) 。最后一种是良好的编码习惯,通常应该这样做!我会解释。当您优化代码段而不进行概要分析以了解它们是否确实是瓶颈时,就不会出现错误的优化(读取过早/微优化)。在这种情况下,您将根据自己的假设,传闻和未记录的行为进行优化。如果它被记录下来并且以更有效/更合理的方式(不管它多么小)来做某件事,我称它为良好的优化。正如其他人所说,就赢得良好业务而言,这两种都有弊端,而且几乎没有利弊,但如果它不能完全击败可读性,那么我还是做后者,而不是前者。是的,可读性/可维护性是最重要的,这与您划清界限的位置有关。 br />
您对特定问题的依赖关系可能会发生变化,在完成应用程序的逻辑部分之前花任何时间进行优化都是在浪费时间。我的意思是在相对较早的阶段进行优化。今天您有了一个
List<T>
,到您的应用发布时,您必须将其更改为LinkedList<T>
,现在所有基准测试都浪费了时间和精力。占代码的5%(大多数是sql的代码),优化其他95%的代码不会给客户带来任何好处。反过来意味着更难的可维护性和更多的时间花费,这反过来又意味着您赚的钱更少。您的团队通过调试和维护该代码而必须排放的温室气体很容易使您通过1%的性能提升为全世界节省的碳足迹。 它通常不会为您带来预期的性能。在SO上看到这个问题,优化在哪里出错了。实际上,它可能会产生不利影响。那就是未记录的行为的问题。
无论如何,大多数现代编译器都会为您做到这一点。
我将给出一些不良和良好的优化示例:
不好-
使用较小的整数类型代替
Int32
。 )避免封闭变量
string p;
foreach (var item in collection)
p = ...;
在串联字符串时使用
++i
代替字符串,例如: br /> string me = 'i' + "me myself"; // something along that line - causes boxing
优点(来自.NET世界。应该不言而喻)-
双重查找
if (Dictionary<K, V>.TryGetValue(K, out V))
do something with V
而不是
if (Dictionary<K, V>.ContainsKey(K))
do something with Dictionary<K, V>[K]
全部加载
>
DirectoryInfo.EnumerateFiles();
而不是
DirectoryInfo.GetFiles();
两阶段铸造:
s = o as string;
if (s != null)
proceed
而不是
if (o is string)
s = (string)o;
如果顺序不重要
if (counter < X || expensiveFunction())
代替
if (expensiveFunction() || counter < X)
拳击
void M<T>(T o) //avoids boxing
{
}
而不是
void M(object o)
{
}
如果您问我这些功能是否具有明显的性能优势,我会拒绝。但是我建议人们应该使用它们,因为它源于对这些结构行为的理解。当您只能打1个电话时,为什么还要打两个电话?从哲学的角度来看,它是良好的编码实践。而且1和3严格来讲也不太可读,但是它们会胜过可读性吗?不,不多,所以我用。现在,这就是关键-保持良好的性能与可读性比率。就是这样,它是关于画线的位置。
#29 楼
“值得”需要上下文,例如,编写,读取和维护的过程要简单得多,而使用户得到响应的速度更快,交互性也要快得多,因此他们等待的时间更少。如果我不得不长途跋涉去拯救那些便士,省下几便士买一罐苏打水对我没有多大好处,尤其是考虑到我最近很少喝苏打水。每购买一百万罐苏打水,每罐节省几便士可能是一笔不小的数目。便宜几个便士,另一个便宜,而我选择一个更贵,因为我更喜欢他们的帽子,这似乎是愚蠢的悲观案例。
我经常发现人们称其为“微观优化”似乎奇怪地是缺乏度量,上下文和用户端讨论,而如果应用这些优化并非绝对的话,那么应该绝对考虑这三种优化。对我来说,如今适当的微优化与诸如内存布局和访问模式之类的东西有关,尽管它们看起来像是“微”,但它们实际上并不是微的。
我设法做到了很久以前,通过“微优化”,将体积相同的输出(通过自动测试确保)的操作从24秒降低到25毫秒(快960倍),输出相同(通过自动测试确保),而算法的复杂性没有变化。 (最大的变化来自内存布局的更改,将其缩短到大约2秒钟,然后剩下的就是SIMD和对VTune中的高速缓存未中的进一步分析以及对内存布局的一些重新安排)。
Wolfire在此介绍了该技术,他为所需的时间而苦苦挣扎:
http://blog.wolfire.com/2009/11/volumetric-heat-diffusion-skinning/
我的实现设法在几毫秒内做到了这一点,而他正努力将其降到不到一分钟:
我从24秒“微优化”下来到25毫秒,这改变了工作流程。现在,艺术家可以以超过30 FPS的速度实时更改其装备,而无需每次对装备进行任何小改动都等待24秒。这实际上改变了我软件的整个设计,因为我不再需要进度条之类的东西,而一切都变得互动了。因此,在所有改进都没有对算法复杂性进行任何改进的意义上,这可能是“微观优化”,但实际上是相当“大规模的优化”,使原本痛苦的非交互过程成为一种实时的,交互式的方式,完全改变了用户的工作方式。我想要的要点:
好吧,来吧。没有人会争辩说这种改变是“不值得的”。您能够展示出切实的利益;许多所谓的微观优化都无法实现。考虑需要进行任何微优化。
而且我不仅要强调测量,还要强调它的用户端。我是一个奇怪的人,因为我首先是用户/粉丝,然后是开发人员,进入了我当前的领域(以前是gamedev)。因此,我从未对激发程序员(例如解决技术难题)的平凡事物感到兴奋。我发现它们是一个负担,但会通过与其他用户共享的用户端梦想来承受它们。但这有助于我确定是否要进行任何优化,这会对具有真正利益的用户产生实际影响。这是我防范无目标地进行微优化的保障。
实际上,这与分析器一样重要,因为我有同事进行过诸如将多维数据集细分为十亿个面的微优化工作,窒息角色和车辆等现实世界的生产模型。在某种“技术演示”意义上,他们的结果令人印象深刻,但对实际用户几乎没有用,因为他们正在对与实际用例不符的用例进行剖析,测量和基准测试。因此,首先要了解对用户重要的内容非常重要,要么学会像其他人一样思考和使用软件,要么与他们合作(理想情况下是两者,但至少要与他们合作)。对我来说,最重要的是,如果要获取微型数据并开始剃须周期和缓存未命中等等,则是开始真正地善于区分不适合这样做的地方(自然而然地知道我们应该去的所有地方)不能这样做,因为探查器和用户端的理解都非常重要。
评论
好吧,来吧。没有人会争辩说这种改变是“不值得的”。您能够展示出切实的利益;许多所谓的微观优化无法做到。
–罗伯特·哈维(Robert Harvey)
18/12/21在3:01
@RobertHarvey这是我希望提出的观点,因为有些人称之为“微观优化”实际上并不一定是微观的,但它取决于上下文,度量等。没有重点和上下文。 :-D
–user321630
18/12/21在3:03
@RobertHarvey我希望,也许是间接地说,如果“微优化”存在负面环境,那么这种类型往往就没有这些度量,环境和用户端需求。我也可以继续讨论最后一种情况,因为我有一位同事用一种很酷的东西优化了地狱,除非没人用过。我什至认为适当的优化需要对用户端有一定的了解,否则我们可能会分析和调整用户不关心的事情。
–user321630
18/12/21在3:12
一些优化是由迫切需求驱动的,而另一些则是由好奇心(智力追求和冒险主义)驱动的。我们都需要。在Dragon Energy的故事中,这可能不是“紧迫的需求”,因为艺术家显然没有大声抱怨直到每次编辑后24秒才能看到任何渲染结果。实际上,用户可能不知道速度会有多快,除非程序员投入了所有精力来打破速度记录。将自己限制在驱动需求上具有商业意义,但是这样做会错过一些惊人的优化机会或改变游戏规则的人。
–rwong
18/12/21在3:33
说到商业意义,还存在货币化的问题。每一个举动(例如从事性能优化的程序员)都会花费金钱,并且为了使业务有意义,需要收回成本。因此,必须问,如果程序员必须获得业务经理的批准,是否可以“出售”改变游戏规则的速度,或者可以“节省”多少钱。
–rwong
18/12/21在3:36
#30 楼
我会这样说-微观优化是对根本没有瓶颈的事物进行优化的过程。例如,如果您的程序调用了两个函数A和B,并且A花费了100毫秒完成,而B花费了2微秒,则您继续优化函数B。这不仅不重要,而且绝对是错误的。但是优化函数B称为优化而不是微优化。优化的重要性取决于。假设您无事可做,并且您的程序没有错误,那么是的,这很重要。但是通常您有优先级。假设您需要添加/编写函数C。如果您认为编写函数C会比不使用该功能更快地编写程序赚钱,那么请进行优化。否则,追求功能。同样,专注于性能的经验丰富的程序员无需花费大量时间进行优化,他们只是编写快速的程序。至少他们知道使用什么工具,花了几年时间做无意义的(微观阅读)优化。评论
这篇文章很难阅读(文字墙)。您介意将其编辑为更好的形状吗?
– gna
13年5月22日在18:07
评论
你父亲的建议已经过时了。我不会问它可以在多大程度上提高性能。我想问瓶颈在哪里。如果对代码段的性能没有整体影响,那么提高代码段的性能并不重要,最慢的链接将决定速度。在PHP中,这是写到网络上的(除非您可以证明IE措施不是这样)。转化为编写更具可读性的代码更为重要。如果考虑关键词,那么他并没有错。您必须对此有所了解。
我很伤心,因为尚未提及著名的过早优化报价:“程序员浪费大量时间来思考或担心程序非关键部分的速度,而这些提高效率的尝试实际上有很大的负面影响考虑调试和维护时产生的影响。我们应该忽略效率低下的问题,例如大约97%的时间:过早的优化是万恶之源。但是,我们不应该放弃那3%的临界机会。”
您能否提供“世界能源的10%”的来源?
编码人员即使在微级别上也不会考虑代码的性能,他们不是优秀的程序员,与微优化有很大不同。只是很好的编码。