编码时微优化重要吗?


178

最近,我问堆栈溢出问题,找出原因isset()函数比的strlen()快PHP。这引发了关于可读代码的重要性以及是否值得考虑提高代码中微秒级性能的问题。

我父亲是一位退休的程序员,我给他看了答案。他绝对确定,即使是程序员,即使在微级别上也没有考虑其代码的性能,那么他们就不是优秀的程序员。

我不太确定-也许计算能力的提高意味着我们不再需要考虑这些微性能的改进?也许这种考虑取决于编写实际语言代码的人?(在上述情况下为PHP)。

环境因素可能很重要-互联网消耗了世界能源的10%。我想知道在数百万个网站上万亿次复制时,浪费几微秒的代码是多少?

我想最好根据有关编程的事实来了解答案。

编码时微优化重要吗?

我个人对25个答案的总结,谢谢大家。

有时我们确实需要担心微优化,但仅在极少数情况下才需要担心。在大多数情况下,可靠性和可读性更为重要。但是,不时考虑进行微优化并没有什么坏处。基本的理解可以帮助我们在编码时不要做出明显的错误选择,例如

if (expensiveFunction() || counter < X)

应该

if (counter < X || expensiveFunction())

来自@ zidarsk8的示例)这可能是一个便宜的函数,因此更改代码将是微优化。但是,有了基本的了解,您就不必这样做了,因为您一开始就可以正确地编写它。


123
你父亲的建议已经过时了。我不会问它可以在多大程度上提高性能。我想问瓶颈在哪里。如果对代码段的性能没有整体影响,那么提高代码段的性能并不重要,最慢的链接将决定速度。在PHP中,这是写到网络上的(除非您可以证明IE措施不是这样);转化为编写更具可读性的代码更为重要。
马丁·约克

61
如果考虑关键词,那他就没错。您必须对此有所了解。
JeffO 2011年

37
我很伤心,因为尚未提到著名的过早优化报价:“程序员浪费大量时间来思考或担心程序非关键部分的速度,而这些提高效率的尝试实际上有很大的负面影响。考虑调试和维护时产生的影响。我们应该忘记效率低下的问题,例如大约97%的时间:过早的优化是万恶之源,但我们不应该放弃那3%的关键机会。”
Tamara Wijsman

13
您能否提供“世界能源的10%”的来源?
迈克尔·复活节

17
coder does not consider performance in their code even at the micro level, they are not good programmers与微观优​​化有很大的不同。这只是很好的编码。
woliveirajr 2011年

Answers:


90

我既同意也不同意你的父亲。应该尽早考虑性能,但是只有在您真正知道在CPU绑定的小型代码段中花费大量时间的时候,才应尽早考虑微优化。

微优化的问题在于,通常它在完成程序时并没有任何概念来了解程序实际上如何花费不必要的时间。

该知识来自执行性能调整的经验,如本例所示,其中通过一系列诊断和加速步骤采用了一个看似简单的程序,没有明显的效率低下,直到它比开始时快43倍。

它表明,您无法真正猜测或直觉问题出在哪里。如果执行诊断(在我的情况下是随机暂停),则优先暴露相当长一部分时间的代码行。如果您查看这些内容,则可能会找到替代代码,从而将总体时间减少了大约一半。

您尚未解决的其他事情仍需要花费比以前更多的时间,但是由于减少了总时间,这些事情现在所占的比例更大,因此,如果再次执行所有操作,则也可以消除该比例。如果您在多次迭代中继续执行此操作,那么就可以不必进行任何微优化就可以实现巨大的加速。

经过这种经验,当您遇到新的编程问题时,您会认识到最初导致这种低效率的设计方法。以我的经验,它来自数据结构的过度设计,非规范化的数据结构,对通知的大量依赖等。


120

只有数据表明确实如此,微优化才是重要的。

如果性能完全对客户端或用户而言是问题,则针对您开发的需求应具有一些性能数据规范。在开发软件时,应根据这些要求测试系统的性能。如果您不满足性能要求,则需要分析代码库并根据需要进行优化以达到性能要求。一旦达到所需的最低性能,就无需从系统中榨取更多性能,尤其是如果您要再损害代码的可读性和可维护性时(根据我的经验,高度优化的代码可读性较低,可维护的,但并非总是如此)。如果您可以在不降低系统其他质量属性的情况下获得额外的性能提升,

但是,在某些情况下,性能至关重要。我主要在考虑实时系统和嵌入式系统。在实时系统中,更改操作顺序可能会对满足正确操作所需的严格期限产生巨大影响,甚至可能影响计算结果。在嵌入式系统中,通常内存,CPU电源和电源(如电池电源)有限,因此需要减小二进制文件的大小并减少计算量,以最大程度地延长系统寿命。


另一方面,如果在使用较慢功能与较快功能之间存在问题,则没有理由使用较慢功能-就像在isset的情况下一样。
马夫里克

7
@Mavrik是的。如果您有X和Y这两个函数,并且Y的速度比X快(至少在您的特定条件下),那么即使代码仍具有可读性和可维护性,也没有理由不使用Y。但是,如果您不了解Y,并且需要重构代码以使用Y而不是X,并且(该代码段的)性能不是问题,那么就没有理由进行更改。权衡取舍–性能,时间,成本,工作量,可读性/可维护性等。
Thomas Owens

2
我全心全意地同意,我只是想在微优化方面提出这一点-如果在可读性/时间方面不花任何钱,那就去做。否则不要。
马夫里克

+1高度优化的代码可读性和可维护性较低,但并非总是如此。
博兹

在其他情况下,表现很重要:(1)游戏;(2)海量数据;(3)高流量网站;(4)高度复杂的UI的响应能力;(5)应该在后台运行的服务,例如病毒检查;(六)财务;(7)智能手机;等等。它几乎不限于RTS和嵌入式系统等神秘案例。
Rex Kerr

103

每当有人问起优化,我提醒的报价迈克尔·杰克逊A.

程序优化的第一条规则:不要这样做。

程序优化的第二个规则(仅适用于专家):不这样做

维基百科的报价已更正为英式英语。* 8')

第二条规则隐式是分析您的代码,只花时间优化会有所作为的事情。

在汇编中编程时,您父亲的主张是正确的。但这比当今大多数人编写的程序更接近金属。今天,即使尝试优化自己(不进行概要分析),也可能导致代码运行速度比采用更通用的方式执行时要慢,因为这种通用方式很可能由现代JIT编译器进行优化。

即使在C语言中,您也必须非常擅长优化,才能比编译器更了解如何优化代码段。

如果您不熟悉Ulrich Drepper在他的优秀论文《每个程序员应该了解的内存》中所谈论的内容,那么您甚至可能在尝试优化自己时也处于失败者地位。但是,与论文标题相反(实际上是对David Goldberg同样出色的“每个计算机科学家应该知道的浮点算术知识”表示敬意),没有这种理解水平并不一定会阻止您成为一名优秀的程序员,只是另一种程序员。

isset()strlen()PHP中

我不了解PHP,因此实际上并不清楚isset()要做什么。我可以从上下文中推断出它,但这意味着它对PHP初学者来说同样是晦涩难懂的,甚至可能导致更有经验的程序员大吃一惊。这是一种惯用的语言,会使维护成为一场噩梦。

不仅如此,而且不能保证isset()总是会效率更高,仅因为它现在效率更高。现在,优化可能不是明年或十年内的优化。CPU,系统,编译器会随着时间的推移而改进和变化。如果PHP的性能strlen()有问题,则将来可能会修改PHP,那么可能需要删除所有isset()优化,以再次优化代码。

每个优化都有可能成为将来的反优化方法,因此应将其视为可能的代码味道,并将其降至最低。

个人经验的例子

作为这种反优化的一个示例,我曾经不得不清理一个巨大的代码库,其中填充了该格式的代码,if x==0 z=0 else z=x*y因为有人假设浮点乘法总是比分支要贵。在原始目标体系结构上,这种优化使代码的运行速度提高了一个数量级,但时间却在变化。

当我们尝试在高度流水线化的更现代的CPU上使用此代码时,性能非常糟糕-这些语句中的每一个都会导致流水线刷新。简化所有这些代码行,z=x*y使程序在新架构上的运行速度提高一个数量级,从而恢复了因反优化而损失的性能。

我们通常需要优化今天的问题是非常对,我们必须优化20年甚至10年前的有所不同。

然后,我们担心这样做每个时钟周期最多的工作,现在我们更可能是担心管道刷新,分支预测失误,并在CPU级高速缓存未命中,但是锁和进程间通信正在成为很多更显著随着我们向多进程和多处理器体系结构。Drepper的论文确实可以帮助理解许多这些问题。


3
您要避免管道刷新和高速缓存未命中:D它们的成本太高了。但是只有在执行它们的代码部分才能执行。
deadalnix

7
我要补充的一件事是,编译器已经走了很长一段路,并将为您优化很多东西。AFAIK,它们比棘手的东西更好地优化了清晰易读的代码。
Becuzz

3
+1提供了一个浪费时间的微优化的真实例子,并揭示了迈克尔·杰克逊是一名程序员。
博兹

1
+1例如。它完美地说明了为什么您应该将琐碎的转换留给编译器。
back2dos

1
@Rex Kerr>例如,代价来自分支,这会导致CPU的管道刷新。浮点乘法也很昂贵。更高级的取决于FPU和运行代码的CPU的管道长度。我不感到惊讶的是,该代码在较旧的CPU上运行速度更快,而这些CPU的流水线较短且FPU的效率低于当前CPU。
deadalnix

84
  1. 编写干净,简洁,简单且易于解释的代码。
  2. 进行性能测试以确定瓶颈。
  3. 优化关键部分。

根据经验:95%的代码有5%的时间运行。在对代码进行概要分析/基准测试并查看有95%的时间运行的5%之前,没有必要进行优化。

每个白痴都可以进行微优化,任何体面的编译器/运行时都可以为您做到这一点。
优化好的代码是微不足道的。编写优化的代码,然后尝试使其变得更好,最好是乏味的,最坏的情况是不可持续的。

如果您非常在意性能,则不要将PHP用于性能关键的代码。找到瓶颈,并使用C扩展名重写它们。即使在混淆点之外对PHP代码进行微优化,也不会获得几乎相同的速度。

就个人而言,当我开始编程时,我非常喜欢进行微优化。因为很明显。因为它会很快奖励您。因为您不必做出重要的决定。这是拖延的完美手段。它使您可以逃避软件开发的真正重要部分:可扩展,灵活,可扩展,健壮的系统的设计。


2
在Bugzilla开发人员指南中,可以找到对我最好的答案:“如果您尝试变得聪明而不是可读性,那么也许您是想使事情“更快”?如果是,请记住:不要在知道问题存在之前就解决问题,如果您不知道(通过实际的详细测试)您的代码运行缓慢,则不必担心使其变得“更快”。优化-许多程序员正在不断解决没有人遇到过的问题。不要那样做。” bugzilla.org/docs/developer.html#general
Marco Marco

7
我通常都同意-除了一行内容,我认为“每个白痴都认为他们可以进行微优化” ...;)
Nim

@Nim:观点;)
back2dos

26

我会同意你父亲的看法:“如果一个程序员即使在微观水平上也没有考虑其代码的性能,那么他们就不是一个好的程序员。” 关键是“考虑性能”。这不等于“在每一步都进行微优化”。

我同意其他大多数意见-曾经使C程序更快的功能可能在今天还不行-但还需要考虑其他严肃的事情:我应该使用C还是C ++?如果您经常使用带有简单重载运算符的类,则它们可能会降低性能。有关系吗 这取决于您的应用程序,但是即使您不考虑它,您也不是一个非常好的程序员。有些人可能会考虑大约2毫秒然后将其关闭,但我认为有太多人甚至根本没有考虑它。

现实情况是,通过优化,代码将变得更难阅读。代码将花费更长的时间来编写。代码的速度会快一点到数量级之间(这是罕见的)。您的客户可能不会知道其中的区别。

另一个现实是人们喜欢重用代码,代码的最终位置可能与您编写代码时完全不同。突然之间,人们可能会在乎。

例如,假设您在PC或游戏机上编写了《愤怒的小鸟》之类的东西。您无视物理系统和图形系统的优化-因为2.5 GHz双核基本上是目前的最低要求,并且您的游戏运行良好。然后,智能手机问世,您想移植它。哦,该死的600 MHz ARM内核?

想想一个网站-在一个周末像“ 热”或“不”之类的东西。您可以使用任何方便的数据库,在考虑到快速发展的情况下编写所有内容,通过向您的朋友发送URL来启动。三个月后,您的服务器因过载而濒临崩溃,无法采取任何措施来扩大规模。它一直在发生。最大的网站上的电费单以数百千瓦甚至兆瓦为单位。考虑一下,通过代码优化可以节省兆瓦。

就像你父亲说的,你至少必须考虑一下。大多数人甚至都不知道桌面上有多少性能,并以“过早的优化”和“不做”的快速技巧来掩盖它的性能。这些不是优秀的程序员。

在这些站点上这不是流行的观点。再见声望点...


3
当然,您应该考虑一下它(在脑后),并且通常会拒绝它,除非它被证明是值得的。您需要考虑的是,优化通常会降低代码的可读性,并且可能会使编码和维护所需的时间增加大约10倍。如果程序不占用大量CPU,则通常不需要。认识到您的编译器通常在优化方面比您要好得多,并且许多优化实际上会损害性能。如果不值得花时间测试您的优化和配置文件,那么就不值得花时间进行优化。
jimbob博士2011年

3
你愤怒的小鸟例子正好说明了为什么你应该不会过早优化。从台式机到控制台再到移动设备的移植中,您正在(至少)处理三种截然不同的硬件,对一种硬件的优化可能会损害而不是对另一种硬件的帮助。更糟糕的是,优化会使代码更难于理解,因此难以移植。当然,从一开始就选择高效的算法,但是当实际数据告诉您每个平台的问题出在哪里时,可以在性能调整阶段保留微优化。
Caleb

@Caleb:《愤怒的小鸟》示例确实说明了为什么不针对特定硬件进行优化。它还说明了如何构建整个应用程序而无需费心进行更常规的“ C级”优化,然后就不知所措了。实际上并没有被烧毁,但是有超出原始意图的麻烦。
phkahler 2011年

25

让我们先来看一下您的情况:PHP

  • 我不认为PHP是一种语言(因为它的性质和主要应用领域),您不必担心这些“微优化”。PHP代码主要通过操作码缓存进行了优化。
  • 用PHP编写的程序不受CPU限制,它们大多受I / O限制,因此无论如何这些优化都不值得您花时间。
  • 您必须优化的所有内容都应该隐藏在C扩展中,然后动态加载到PHP运行时中
  • 因此,您可以看到,通过微优化PHP中的代码,我们没有动力-另一方面,如果您花时间使PHP代码更具可读性和可维护性,那将为您带来更多收益。

一般来说,

我不会花很多时间在“ TOOOOO”上以诸如PythonRuby之类的动态语言来优化我的代码-因为它们不是为CPU密集型数字运算任务而设计的。他们解决了不同类别的问题,在这些问题中,以精细的方式(易于阅读和维护)对现实世界进行建模(称为表达性)比速度更为重要。如果速度是头等大事,那么它们一开始就不会动态变化。

对于已编译的程序(C ++,Java),优化更为关键。但同样,首先,您必须查看所编写程序的性质/领域/用途。您还应该仔细权衡微优化的时间与该优化的收益。如果您需要更多的优化,那么您不妨考虑下一个步骤-并在汇编器中编写这些代码。

因此,回答您最初的问题-“编码时进行微优化是否重要?” -答案是-取决于-

  • 您正在执行哪种操作:应用程序域,复杂性?
  • 微秒级的速度提升对您的程序真的重要吗?
  • 哪种优化最有益?它可能不总是代码优化,而是外部的。
  • 您在进行微优化时花费了多少“速度”(收益)?
  • 是否可以通过更改硬件,RAM和处理器,并行执行代码或在分布式系统上以其他方式实现更快的速度?

微观优化(为此进行代码优化)不仅耗时,而且“扭曲”了代码的自然可读性,从而使维护变得繁重。始终认为这是万不得已的方法-始终尝试通过采用比优化单个代码文件更好的硬件和更好的体系结构来优化整个应用程序。


18

似乎有很多答案说微优化是

关于权衡的所有方面-性能,时间,成本,工作量,可读性/可维护性等。

但是我知道有些优化不会影响可读性,我只是想做些有趣的事情。我在一些学校作业(全部基于速度)中看到,编写条件语句时考虑微优化总是很不错的事情,例如:

if (counter < X && shouldDoThis()) // shouldDoThis() is an expensive function

永远比

if (shouldDoThis() && counter < X ) 

有很多方法可以像这样“加速”您的代码,并且差异通常可以忽略不计(尽管并非总是如此),但是如果我这样写,我会感觉更好。

我不知道是否有人认为这是实际的优化,但是我认为程序员在编写代码时应该知道并考虑这些事情。


2
对于此特定情况,这可能并不重要。不过,我认为这是非常,这样,当它能够认识到这样的优化重要的的事,你不必花费不必要的时间分析和事后优化。
tskuzzy 2011年

4
这是一个非常危险的例子。一个优化应该永远不会改变自己的行为。甚至暗示这cheap() && expensive()是一种优化,它expensive () && cheap()邀请人们盲目地用一个人替换另一个人,而不考虑它所创造的重大语义变化(在&&短路运算符所在的语言中)。
Mark Booth,

5
如果这些功能没有副作用,则它们是等效的,并且更快。如果它们确实有副作用,则一开始不应该这样编写代码。我什至会说这是出于习惯而应该做的-除非它实际上改变了行为。
phkahler

3
@MarkBooth在这里我必须同意phkahler,这些功能都不应该有副作用!if语句中condionos的顺序必须不影响程序的结果。我的示例最好写成if (x<100 && isPrime(x)),以使其更加清楚。
zidarsk8 2012年

1
@ zidarsk8-如果优化更改了执行速度以外任何其他内容则它不是优化。作为程序员,我们通常必须务实,有时这意味着我们不能保证与短路运算符一起使用的所有函数都是纯函数-尤其是当我们的代码调用无法控制的第三方库时。在这种情况下,您必须注意不要鼓励没有经验的程序员以优化的名义引入错误。
Mark Booth

11

在我职业生涯的早期,诸如“不要进行微优化”之类的笼统声明引起了很多混乱。一切都是偶然的。因此,人们说“最佳实践”而不是“做到这一点”的原因。

考虑到所有情况,“最佳实践”是最佳选择。例如,应使用LINQEntity Framework代替内联SQL。在我公司,我们使用SQL Server 2000。SQL Server 2000不支持实体框架。最佳做法要求:

  • 卖掉我老板的想法是购买新版本的SQL Server,这意味着数千美元。
  • 向开发人员推销学习新技术的想法。

我从经验中知道这不会发生。因此,我可以辞职,无休止地坚持下去或不遵循最佳实践。

决策背后存在影响整体结果的政治,技术和金钱考虑。做出决定时请记住这一事实,并明智地选择自己的战斗。

在天堂之下,每件事都有一个季节,一个活动的时间。


1
顺便说一句,您可以将Dapper用作内联SQL的微型ORM替代方案。

2
LINQ and Entity Framework should be used in lieu of inline SQL-直到您实际需要内联SQL来优化某些内容为止;EF生成的SQL并非总是最优的。
罗伯特·哈维

1
FWIW,如果你的老板是担心SQL 2K8的许可成本(或任何其他可能是电流),你应该点出它的年龄足以对EOL未来行动非常快(如果不是的话)
沃伦

@warren-有些公司没有考虑到此类问题。对于某些人来说,如果它仍然“起作用”,则它们将不会升级。通过工作,我的意思是服务器仍在运行。我们已经看到EF缺乏支持。这根本不足以说服他们花钱。
P.Brian.Mackey 2011年

1
众所周知,您可以在SQL 2000中使用EF。设计器不起作用,但是实际的实体框架确实支持SQL2000。要解决设计器的局限性,您可以使用相同的架构在sql 2008 express中创建本地数据库作为sql 2000数据库,请设计人员将其指向生成所有类,然后进入.edmx文件,并将目标数据库版本更改为2000,然后将连接字符串指向sql server 2000数据库。不是最好的解决方案,但是如果您不能升级,它就可以工作。
尼尔

8

这始终是一个权衡。

首先,计算机行业的最后关头是金钱。作为开发人员,您需要做的是为客户创造价值,以便您获得收益(这过于简单化了,但要点在这里)。

开发人员时间要花钱。机器动力也要花钱。通常,第二个成本要比第一个成本低得多。因此,拥有可读性和可维护性的代码是资本,因此开发人员可以花费大部分时间来交付价值。

在某些情况下,微优化可能很重要。但是它们通常涉及可读性较低的代码或扩展性较小的代码(这不是链接示例的情况,但总的来说是这样)。这将花费开发人员的时间。这次比机器动力更昂贵,这是浪费。

其次,在大型项目中进行微观优化会使维护/发展变得越来越难。这样做的问题是,在发展时,现在可能无法进行其他优化。随着应用程序的不断发展,通常您最终会得到比没有进行这些优化的解决方案要慢的解决方案。

第三,优化通常是不明确的,因为算法复杂性通常会克服如果数据集增长而可能进行的任何微优化。可悲的是,由于微优化使您的代码难以维护/演化,因此这些优化可能更难进行。

有时,价值在于这种优化(考虑延迟关键程序,例如视频游戏或飞机的自动驾驶仪)。但这必须得到证明。通常,您的程序大部分时间都花在有限的代码中。无论您进行什么微优化,如果没有发现瓶颈并进行工作,您都无法以任何有价值的速度更快地完成程序。

如您所问,您的问题表明您没有在实际程序中对该问题进行基准测试。在这种情况下,您可能会成功,并注意到它是否更快。所以您在有任何问题之前先问过这个问题。这就是问题所在。您以错误的方式处理优化问题。

由于维护和升级通常比微优化更有价值,因此在执行任何操作之前,请确保具有正确的界面。然后,如果程序的各个部分足够抽象,那么您可以微优化一个,而不会弄乱整个过程。这要求您的界面运行足够长的时间才能被信任。


“总会有一个权衡”。的确,如果程序处于折衷曲线上减少一个变量将增加另一个变量。以我的经验,大多数程序都离折衷曲线不远,并且有足够的空间减少这两个变量。
Mike Dunlavey

+1维护和改进比微优化更有价值。尽管我确信计算机行业不仅仅是金钱?例如,开源,教育,创新,治理,社区等。我确信可以从中找到钱,但是大多数情况都是如此。
博兹

@Boz kay>这部分是正确的。首先,因为您的老板和客户通常对那些事一无所知,并且对金钱不感兴趣。如果要推广一些开源工具,则必须告诉他们如何改善公司品牌或如何降低开发成本。另外,使开发人员满意是在公司中获得良好开发人员的一种方法。优秀的开发者可以赚钱(主要是投入质量和创新)。最后,金钱是关键。我在我的linux计算机上写了一个很棒的免费软件支持者。教育也是如此。
deadalnix 2011年

8

性能是特色

杰夫·阿特伍德(Jeff Atwood)的文章是关于构建高性能网站的出色文章,并且这样做的重要性...

也就是说,在需要之前不要专注于微优化。您可以执行更多具有成本效益的优化。专注于体系结构,而不是代码。我看到的大多数运行缓慢的网站都存在高级问题(不必要的Web服务层,不良的数据库设计,过于复杂的体系结构),不仅影响性能,而且根深蒂固且难以修复。

建立网站时,客户端代码和数据库逻辑比服务器端代码更容易引起性能问题。像其他任何东西一样,如果您会遇到性能问题,甚至可以更好地分析代码,便可以尽早找到它们。


7

开发人员时间花费的时间超过计算机时间。通常这就是您要优化的内容。但:

  • 微观优化和算法复杂性之间存在差异。花足够的时间来确保您使用的算法正确。
  • 确保您问的是正确的问题,select (select count(*) from foo) >= 1而不是与select exists(select 1 from foo)
  • 某些语言习惯用法之所以流行是因为它们速度更快。可以使用它们,因为大多数流利的语言用户都会熟悉它们。(您的示例就是一个很好的示例)。

7

您想优化什么?

  • 软件性能如何?
  • 可靠性?
  • 程序员的生产力?
  • 消费者满意度?
  • 电源效率?
  • 可维护性?
  • 上市时间?
  • 成本?

“优化”并不总是意味着使代码运行得尽可能快。有时候,找到绝对最快的方法来完成某件事很重要,但这实际上并不是大多数代码中都常见的。如果用户没有注意到50到100微秒之间的差异,那么在仅偶尔运行的代码中,两者之间实际上就没有差异。这是一个例子:

如果您需要不断更新用户输入长度的显示以及两个例程确定一个长度远小于两次连续击键之间的时间所花费的时间,那么哪个例程确实无关紧要你用。另一方面,如果需要确定十亿个字符串的长度,则可能需要密切注意不同例程之间的性能差异。在第一种情况下,您可能希望编写易于理解和验证的代码。在第二种情况下,您可能愿意以可读性为代价。

无论如何,如果要优化代码,则应在进行任何更改之前和之后对代码进行概要分析。如今的程序非常复杂,以至于通常很难分辨出瓶颈在哪里。概要分析可帮助您优化正确的代码,然后证明您所做的优化确实有效。

您没有说父亲何时退休或他做了什么样的编程,但是他的反应不足为奇。从历史上看,内存,辅助存储和计算时间都很昂贵,有时甚至非常昂贵。这些天,与程序员的时间相比,所有这些东西变得非常便宜。同时,处理器和编译器已经能够以程序员无法匹敌的方式优化代码。程序员使用小技巧在这里烧掉一些机器指令的时代几乎已经一去不复返了。


1
+1更不用说在过去的几年中,移动设备再次高度依赖于代码优化。没有编写优化代码或至少认为没有优化代码的人可能很难让他们的CPU密集型应用程序在移动设备上流畅运行。
Styler

+1非常类似于您的可能优化列表。他使用了assembly / fortran
Boz

@Styler:移动设备拥有带GB内存的四核CPU很快,我们已经拥有双核智能手机。
Lie Ryan

@Lie Ryan:是的,这是真的,但是像大多数开拓者一样,他们不得不乘木船旅行;)
Styler

7

在编写代码时进行微优化并不重要。优化应该在探查器的帮助下完成,从而在需要的地方优化代码。

但是,程序员在编写代码时应尽量避免做一些明显的愚蠢的事情。

例如,不要在循环内重复执行昂贵的操作。将值存储在循环外的变量中并使用它。不要在经常调用的函数中一遍又一遍地执行字符串比较或正则表达式之类的事情,当您可以上一层级时,进行比较并将其变成整数或函数引用或派生类。

这些内容对于有经验的程序员来说很容易记住,并且几乎总是可以提高代码质量。


意识到我需要在问题编辑中清楚一点,我实际上是在说同样的话-我已对其进行了更新。
博兹

7

在决定优化方法时,请始终记住阿姆达尔定律。请参阅链接以获取精确的数学信息;要记住的精妙声明是:

如果程序的一部分占其运行时间的10%,并且优化该部分以使其运行速度提高一倍,则该程序的整体运行速度只会提高5%。

这就是为什么人们总是说不值得优化程序中不占总运行时间百分之几的部分的原因。但这只是更一般性原则的特例。阿姆达尔定律告诉您,如果您需要使整个程序的运行速度快一倍,则需要将每个程序的平均速度提高50%。它告诉您,如果您需要处理20 GB的数据,只有两种方法可以使读取速度比从磁盘读取20 GB的时间更快:获得更快的磁盘或减小数据容量。

那么,阿姆达尔定律对微优化有何看法?它说,如果全盘适用,他们也许值得。如果您可以将程序中每个功能的运行时间节省百分之一,那么恭喜您!您已使程序加速了百分之一。那值得吗?好吧,作为一个编译器专家,我很高兴找到可以做到这一点的优化,但是如果您是手工完成的话,我会说寻找更大的东西。


1
+1是Amdahl的报价,但我不同意“要使整个程序的运行速度快两倍,您需要加快每个程序的速度”。我会说您实际上并没有加快任何“步伐”。相反,您会发现不必要的工作并将其消除。如果程序比玩具大,则尤其是函数调用。关于性能的许多常见想法似乎完全忽略了找到调用树的整个不必要分支(可以是单个指令)并将其关闭的重要性。
麦克邓拉维

魔鬼出现在“平均”一词中。从数学上讲,将程序加速50%的情况下,平均每个程序段必须加快50%。现在,如果您可以将程序划分为一个占用了运行时75%的工作,而另一个占用了25%的工作,并将前一个工作的速度提高了3倍,那么尽管对后者没有做任何事情,但总体上可以使您获得50%的工作。但是更常见的情况是,有数十个“作业”占用的运行时间少于5%,然后您必须加快工作速度或摆脱其中的许多工作。
zwol 2011年

我认为有一个更常见的情况。有一项“工作”占用了50%的时间,但是您实际上并不需要它,因此您将其完全删除,将总时间减少了该数量,然后重复执行。我知道这很难接受-程序可能会花费大量时间做事(事后看来)是完全不必要的。但是,这是我的典型例子
Mike Dunlavey

6

这取决于您所处的开发阶段,最初开始编写东西时,微优化不应该被考虑,因为与使用微优化相比,使用良好的算法将获得更多的性能提升。另外,考虑一下您正在开发什么,因为对时间敏感的应用程序将比常规业务应用程序从微优化考虑中看到更多的好处。

如果您正在测试和扩展软件,那么微优化可能会损害您的利益,它们往往会使代码更难阅读,甚至会引入他们自己独特的bug集,这些bug需要修复,以及其他需要修复的问题。

如果您实际上是从用户那里收到有关缓慢代码的投诉,那么也许值得考虑,但前提是其他所有问题都已解决,即:

  • 代码编写正确吗?
  • 应用程序是否可以访问其数据而没有任何问题?
  • 可以使用更好的算法吗?

如果所有问题都得到了解答,而您仍然遇到性能问题,那么可能是时候开始在代码中使用微优化了,但是其他更改(例如,更好的代码,更好的算法等)可以使您满意比微观优化更能提高性能。


5

执行速度是影响程序质量的众多因素之一。通常,速度与可读性/可维护性成反比。在几乎所有情况下,代码都必须是人类可读的,以便可以维护代码。当速度是必不可少的条件时,唯一会损害可读性的时间。使代码比完全可读性/可维护性所允许的速度更快的要求几乎从未适用,但是在某些情况下会适用。要记住的主要事情是,微优化代码通常是hacky代码,因此,除非在某处有已定义的要求,否则解决问题几乎总是错误的方式。例如,用户几乎永远不会注意到CRUD操作中0.5秒和1秒执行时间之间的差异,因此,您无需进入Assembly-interop-hackfest即可到达.5秒。是的,我可以驾驶直升飞机上班,它的飞行速度是它的10倍,但我并不是因为价格高和直升飞机很难飞行这一事实。当您不必要地对代码进行微优化时,这正是您正在做的事情:增加不必要的复杂性和成本以达到多余的目标。


5

当您遇到限制时,微优化很重要。您关心的是内存,吞吐量,延迟或功耗。请注意,这些是系统级别的特征。您不需要(也不能)以各种方式优化每个功能。

嵌入式系统更可能需要微优化,因为约束更容易受到打击。但是,即使进行微优化也只能让您走到这一步。您无法对不良设计进行微优化。在系统中进行良好设计的重点是,您可以对整个系统进行推理。需要进行微优化的组件应该以不会损害系统设计的方式进行整洁地暴露和优化。

请注意,今天的小型“嵌入式”系统可能非常接近于过去的VaxenPDP-11,因此这些问题过去更加普遍。在执行现代通用商业计算的现代通用系统上,微优化是很少见的。这可能就是您父亲接任他职位的部分原因。

但是,处理纳秒,毫秒,秒或小时无关紧要;问题是相同的。必须在系统和您要达到的目的的上下文中对它们进行评估。

这是我最近在Stack Overflow上回答的一个问题示例,该问题针对需要微优化的情况:嵌入式系统的开源视频编码器


4

微观优化的最大问题是,它会使您编写难以维护的代码。

另一个问题是取决于计算机配置,有时您的微优化可能会比没有“优化”的性能差。

进行许多微优化会消耗大量时间,与实际上并不重要的事物进行斗争。

更好的方法是编写更清晰的代码,更易于维护,如果遇到性能问题,请运行配置文件以找出真正使代码变慢的原因。而确切地知道什么是真正的坏处,您可以修复它。

我并不是说不进行微优化是编写愚蠢代码的借口。


4

如果您开始担心毫秒,则应考虑放弃PHP并改用C或Assembly。我并不是要这样做,讨论这些数字并使用脚本语言只是没有意义。无论如何,您的代码是否经常使用此命令进行迭代?

这里的环境因素是毫无疑问的,这些服务器无论如何都是24/7运行,并且如果它们确实处理某些事情,则只有当它确实是一个很长时间运行的任务时才有意义。

我们所有人都在键入问题和答案时,很可能是办公室的灯光和计算机所消耗的能量,所消耗的能量远远超过可以合理地应用于应用程序的任何微优化。


+1关闭指示灯或不回答问题。
博兹

4

您应该为任务选择最佳,简单的算法。它需要简单的原因是保持代码可读性。之所以需要最好的原因是为了避免以不良的运行时特性开始。当您知道自己将拥有大型数据集时,请不要盲目选择BubbleSort。但是,偶尔需要10个元素就可以了。

然后,如果分析数据表明您对最佳,简单算法的选择不够好,则可以开始优化(通常以可读性为代价)。


当您的数据几乎只用几个离最终目标相差不大的杂散元素进行排序时,BubbleSort实际上比quicksort或mergesort更好。但是,对于所有其他任务,应使用编程语言为您提供的内置排序功能。这是入门的最简单方法(大多数语言中的内置排序功能都具有良好的性能)。错误的建议:start out with bad runtime characteristic不要故意以不良的运行时特性开始。
Lie Ryan

@Lie,如果您知道数据几乎已排序并且因此可以使用Bubblesort,那么您并不是完全盲目地选择算法...也感谢您指出了错字。

4

我之前已经说过,在这里我会说:“过早的优化是万恶之源”。这应该是任何程序员的中心规则之一。

在某种程度上,代码总会比现在快。除非您手工组装带有特定芯片的组件,否则通过优化始终可以获得一些好处。但是,除非您想为所有工作进行手动包装,否则就必须有一个量化的目标,一旦达到目标,您就说“就足够了”并停止优化,即使仍有明显的性能问题也是如此。面对你

如果它不起作用,那么漂亮,优雅,性能极佳的代码将毫无用处(而“工作”是指在给出所有预期输入的情况下产生预期输出)。因此,始终将生产有效的代码始终放在第一位。在工作之后,您要评估性能,如果缺乏性能,您会寻找方法来改善性能,直到达到足够好的水平。

您必须事先决定一些会影响性能的事情;非常基本的决定,例如您将使用哪种语言/运行时来实现此解决方案。与调用一种方法相比,其中许多方法对性能的影响要大很多数量级。老实说,PHP作为一种脚本语言,已经对性能产生了很大的影响,但是由于很少有脚本站点是使用C / C ++自下而上构建的,因此可以与您可能选择的其他技术(Java Servlets,ASP.NET)相提并论。等)。

之后,I / O消息大小将成为您的第二大性能杀手。即使I / O操作背后的算法高效,对硬盘,串行端口,网络管道等的读写操作通常也可以将程序的运行时间缩短多个数量级。之后,降低算法本身的Big-O复杂性,然后如果绝对必要,则可以通过选择较便宜的方法调用并在较低级别进行其他深奥的决定来“微优化”。


2
+1有效的生产代码应该始终是第一要务。
博兹

2
@Keith,实际上是Knuth首先说的,他的话要多得多。

“使它工作,然后使其按需要的速度工作”,Anon。
约翰·桑德斯

1
宗教实际上是万恶之源,但我离题。
Thomas Eding

4

您提到您的父亲是退休的程序员。在大型机领域工作的程序员必须非常关注性能。我记得在美国海军进行的一次活动中,他们的大型机受到硬件限制,每个用户的内存为64 KB。在那个编程世界中,您必须小心自己的每一点。

现在情况大不相同了,大多数程序员不必担心微优化。但是,嵌入式系统程序员仍然会这样做,并且数据库人员仍然非常需要使用优化的代码。


3

编写代码时应绝对清楚其功能。然后,且仅它太慢时,再返回并加快速度。如果可以理解,总是可以将代码更改为以后更快的代码,但是如果运气好的话,也可以将其更改为清楚。


3

重要的是:

1)某人的生活取决于您的代码。在某人的心率监测器中执行花费25毫秒才能执行的功能可能是个坏主意。

我个人采取两种方法-您可以进行微优化而不会影响可读性-显然您想使用这些优化。但是,如果它影响了可读性,那么请推迟-您将不会获得太多好处,并且从长远来看,它实际上可能需要花费更长的时间进行调试。


2
您的示例仅需注意一些小问题:只要花费必要的响应时间即可完成其他必要的任务,那么心率监视器中耗时25ms的功能就不会成为问题。中断对此有好处。对于仅监视现实世界事件以更新显示器以供人类使用的事物,延迟时间为25ms可能不是问题。
2011年

3

编码时微优化重要吗?

不可以,因为有像JVM.NET这样的平台,其中的代码是为虚拟机编写的,因此尝试优化执行的效果可能不太理想,因为开发人员桌面上的最佳选择不一定与服务器上的相同。在这里,请看一下其中一些高级软件与硬件的距离。考虑到硬件的多样性,在不到一年的时间内推出一种新模型时,针对特定芯片(例如CPU或GPU)优化代码的现实性如何?

这里要考虑的另一个问题是按什么度量标准衡量的性能:执行速度,执行中使用的内存,新功能的开发速度,服务器上已编译或反编译形式的代码大小,可伸缩性,可维护性等。?如果从广义上讲,这个问题就变得微不足道了,但是我不确定您打算在多大程度上采用真正的性能,只要可以通过某种方式对其进行衡量就几乎可以做到。


某些微优化可能会起作用,而有些则可能无法奏效,这是人们可能想知道,与其他工作相比,执行新工作的价值是什么,而其他工作可能被视为具有更高的优先级,例如新功能或修复错误。另一个问题是硬件或软件的升级是否也会破坏其中的某些优化。


1
请注意,您绝对可以在JVM和.NET等平台上进行微优化,它们的形式略有不同。但是,如果将旧的简单C编译器与更现代,高度优化的编译器进行比较,则同样如此:用户可以执行的优化看起来会有所不同。
约阿希姆·绍尔

1

我认为良好的编程和微优化之间存在很大的差异。

如果有两种方法可以完成同一任务,一种方法比另一种方法要快,并且两者具有相同的可读性,则应使用更快的方法。总是。这是很好的编程。没有理由不使用更好的算法来解决问题。甚至记录下来也很容易:给算法名称,每个人都可以在Google上搜索它并找到有关其工作原理的更多信息。

好的算法已经过优化。他们会很快。他们会很小。他们将使用所需的最小内存。

即使使用它们,您的程序仍然不具有这种性能,您也可以考虑对其进行微优化。而且,您必须真正了解该语言才能进行微优化。

而且总会有空间在硬件上花费更多的钱。硬件便宜,程序员昂贵。通过优化何时可以购买硬件,不要花费太多时间/金钱。


1

IMHO 代码的可读性比微优化更重要,因为在大多数情况下,微优化是不值得的。

第二条关于无感微优化

作为我们大多数人,我很疲倦地阅读有关无意义的微优化的博客文章,例如用echo代替print,用$ i ++代替++ $ i或用单引号引起双引号。为什么?因为99.999999%的时间是无关紧要的。为什么?因为99.99%的时间,您最好安装PHP加速器(如APC),或者在数据库列中添加这些缺失的索引,或者尝试避免主页上有1000个数据库请求。

print使用了另一个操作码,因为它实际上返回了一些东西。我们可以得出结论,回声比打印要快。但是,一个操作码不花钱,真的不花钱。

我已经尝试过全新的WordPress安装。该脚本在我的笔记本电脑上以“总线错误”结束之前停止运行,但操作码数量已超过230万。说够了。

因此,在大多数情况下,微优化可节省数百万种操作中的一种,但会使可读性变差。


1

其他答案也很对。但是,我还要补充一点,必须区分过早的优化/微优化,并编写能反映对语言/框架构造行为理解的高性能代码(对不起,最后一个单词找不到) 。最后一种良好的编码习惯,通常应该这样做!

我会解释。当您优化代码段而不进行概要分析以了解它们是否确实是瓶颈时,就不会出现错误的优化(读取过早/微优化)。在这种情况下,您将根据自己的假设,传闻和未记录的行为进行优化。如果它已被记录并以更有效/更合理的方式(不管它多么小)来做某事,我称其为“ 优化”。正如其他人所说,就赢得良好业务而言,这两种都有弊端,而且几乎没有利弊,但是如果它不能完全击败可读性,那么我还是做后者,而不是前者。是的,可读性/可维护性是最重要的,这与划界线有关。

我将在这里重申其他人提出的观点,认为优劣优化是徒劳的:

  1. 您对特定问题的依赖性可能会发生变化,并且在完成应用程序的逻辑部分之前花任何时间进行优化都是在浪费时间。我的意思是在相对较早的阶段进行优化。如今,您List<T>的应用程序开始运行,到了发布时,您不得不将其更改为LinkedList<T>,现在进行所有基准测试都浪费了时间和精力。

  2. 通常,应用程序的真正瓶颈(可衡量的差异)可能是代码的5%(大多数是sql的),而优化其他95%的代码不会给客户带来任何好处。

  3. 通常,“技术上”性能更好的代码意味着更多的冗长性,这又意味着更多的容易出错的代码,这反过来意味着更难的可维护性,以及花费更多的时间,这反过来又意味着您可以获得更少的钱。

  4. 通过1%的性能提升,您为全世界节省的碳足迹很容易与您的团队在调试和维护该代码时必须释放的温室气体相形见war。

不良优化的负面影响尤其是:

  1. 它通常不会给您您期望的性能。在SO上看到这个问题,优化在哪里出错了实际上,它可能会产生不利影响。这就是无证行为的问题。

  2. 无论如何,大多数现代编译器都会为您完成此任务。

我将给出一些不好的优化示例:

不好-

  1. 使用较小的整数类型代替Int32

  2. ++i 用于代替 i++

  3. for而不是foreach(我所见过的最糟糕的情况完全破坏了逻辑)

  4. 避免封闭变量

    string p;
    foreach (var item in collection)
        p = ...;
    
  5. char在字符串串联期间使用而不是字符串,例如:

    string me = 'i' + "me myself"; // something along that line - causes boxing
    

优点(来自.NET世界。应该不言而喻)-

  1. 双重查询

    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]
    
  2. 全部加载

    DirectoryInfo.EnumerateFiles();
    

    代替

    DirectoryInfo.GetFiles();
    
  3. 两阶段铸造:

    s = o as string;
    if (s != null)
        proceed
    

    代替

    if (o is string)
        s = (string)o;
    
  4. 如果顺序无关紧要

    if (counter < X || expensiveFunction())
    

    代替

    if (expensiveFunction() || counter < X)
    
  5. 拳击

    void M<T>(T o) //avoids boxing
    {
    
    }
    

    代替

    void M(object o)
    {
    
    }
    

如果您问我这些功能是否具有明显的性能优势,我会拒绝。但是我建议人们应该使用它们,因为它源于对这些结构行为的理解。当您只能打1个电话时,为什么还要打两个电话?从哲学的角度来看,它是良好的编码实践。而且1和3严格来讲也不太可读,但是它们是否比可读性强?不,不多,所以我用。现在,这就是关键-保持良好的性能与可读性比率。就是这样,它与画线的位置有关。


1

“值得”需要上下文,例如,编写,读取和维护的过程要简单得多,而使用户产生响应的速度明显快得多,交互性强,因此需要更少的时间等待。

如果我不得不长途跋涉去节省那些便士,省下几便士来买一罐苏打水对我没有多大好处,尤其是考虑到这些天我很少喝苏打水。每购买一百万罐苏打水,每罐节省几美分可能是一笔大买卖。

同时,当两个人就在我身旁时,节省了几便士,而一个人却提供了完全相同的东西,但价格便宜了几便士,而另一个则没有,我选择了更贵的一个,因为我更喜欢他们的帽子似乎是一个愚蠢的案例。悲观。

我经常发现人们所谓的“微优化”似乎没有度量,上下文和用户端讨论,而如果应用这些微不足道的话,绝对应该考虑这三种优化。对我来说,如今适当的微优化与诸如内存布局和访问模式之类的东西有关,尽管它们看上去似乎是“微”的,但实际上并不是微的。

不久前,我设法将操作从24秒降低到25毫秒(快960倍),输出相同(通过自动测试确保),而对于体积热扩散蒙皮,通过“微优化”(最大的优化来自内存布局的更改,将其缩短到大约2秒钟,然后剩下的就是SIMD之类的东西,并且进一步分析了VTune中的缓存未命中,并且对内存布局进行了一些进一步的重新安排)。

沃尔夫(Wolfire)在这里解释了该技术,他为所需的时间而苦苦挣扎:http : //blog.wolfire.com/2009/11/volumetric-heat-diffusion-skinning/

我的实现设法在几毫秒内做到了这一点,而他正努力将其降到不到一分钟: 在此处输入图片说明

在我对其进行“微优化”后,它从24秒降低到25ms,这改变了工作流程。现在,艺术家可以以超过30 FPS的速度实时更改其装备,而无需每次对装备进行任何微小更改都等待24秒。这实际上改变了我软件的整体设计,因为我不再需要进度条和类似的东西,而一切都变得互动了。因此,在所有改进都没有对算法复杂性进行任何改进的意义上,这可能是“微优化”,但实际上是一个相当“巨大的优化”,使原本痛苦的,非交互式的过程成为一种实时,交互式的方式,完全改变了用户的工作方式。

测量,用户端要求,上下文

我真的很喜欢罗伯特的评论,也许我没能说出我想要的观点:

好吧,来吧。没有人会争辩说这种改变“不值得”。您能够展示出切实的利益;许多所谓的微观优化无法做到。

尽管这是在经常对实时性要求很高的性能至关重要的领域中进行的,但这是我唯一考虑进行任何微优化的唯一时间。

我不仅要强调测量,还要强调它的用户端。我是一个奇怪的人,因为我首先是用户/粉丝,然后是开发人员,进入了我当前的领域(以前是gamedev)。因此,我从未对激发程序员(例如解决技术难题)的平凡事物感到兴奋。我发现它们是一个负担,但会通过与其他用户共享的用户端梦想来承受它们。但这有助于我确定是否要进行任何优化,这会对具有真正利益的用户产生实际影响。这是我防止漫无目的地进行微优化的保障。

在我看来,这实际上和分析器一样重要,因为我有同事从事过将多维数据集细分微细化为十亿个方面的工作,而这些工作只能扼杀角色和车辆等现实生产模型。在某种“技术演示”意义上,他们的结果令人印象深刻,但对于实际用户而言几乎没有用,因为他们正在对与实际用例不符的用例进行剖析,测量和基准测试。因此,首先要了解对用户重要的内容非常重要,要么学会像其他人一样思考和使用软件,要么与他们合作(理想情况下是两者,但至少要与他们合作)。


2
好吧,来吧。没有人会争辩说这种改变“不值得”。您能够展示出切实的利益;许多所谓的微观优化无法做到。
罗伯特·哈维

1
@RobertHarvey这是一种我希望说明一点,因为一些人称之为“微优化”是不起作用一定微观的,但它是如此依赖于上下文,测量等isset对比strlen似乎更专注微乎其微缺少上下文和度量。:-D
龙的能量

1
@RobertHarvey我希望,也许是间接地说,如果“微优化”存在负面环境,那么这种类型往往就没有这些度量,环境和用户端需求。我也可以继续讲最后一种情况,因为我有一位同事用一种很酷的东西优化了地狱,除非没人用过。我什至认为适当的优化需要对用户端有一定的了解,否则我们可能会分析和调整用户不关心的事情。
Dragon Energy

1
一些优化是由迫切需求驱动的,而另一些则是由好奇心(智力追求和冒险主义)驱动的。我们都需要。在Dragon Energy的故事中,这可能不是“紧迫的需求”,因为艺术家显然没有大声抱怨直到每次编辑后24秒才能看到任何渲染结果。实际上,直到程序员花了所有心血来打破速度记录,用户才可能知道速度有多快。将自己限制在驱动需求上具有商业意义,但是这样做会错过一些惊人的优化机会或改变游戏规则的人。
rwong

1
说到商业意义,还存在货币化问题。每一步(例如,致力于性能优化的程序员)都需要花钱,并且为了使业务有意义,需要收回成本。因此,如果程序员必须获得业务经理的批准,就必须问是否可以“出售”改变游戏规则的速度,或者可以“节省”多少钱。
rwong

0

我这样说-微观优化是对根本没有瓶颈的事物进行优化的过程。例如,如果您的程序调用了两个函数A和B,并且A花费了100毫秒来完成,而B花费了2微秒,并且您继续优化函数B。那不仅不重要,而且绝对是错误的。但是优化函数B称为优化而不是微优化。优化的重要性取决于。假设您无事可做且您的程序没有错误,那么是的,这很重要。但是通常您有优先级。假设您需要添加/编写函数C。如果您认为编写函数C会比不使用该功能更快地编写程序赚钱,那么请进行优化。否则,追求功能。也,专注于性能的经验丰富的程序员无需花费大量时间进行优化,他们只是编写快速的程序。至少他们知道使用什么工具,花什么年不做无意义的(微观阅读)优化。


这篇文章很难阅读(文字墙)。您介意将其编辑为更好的形状吗?
蚊蚋
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.