作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
凯文·布洛赫的头像

凯文·布洛赫

验证专家 in 工程

Kevin拥有超过20年的全栈、桌面和独立游戏开发经验. 他最近专门研究PostgreSQL、JavaScript、Perl和Haxe.

专业知识

工作经验

8

分享

性能优化是对代码的最大威胁之一.

你可能会想, 不是另一个 那些 . 我理解. 任何类型的优化显然都应该是一件好事, 从它的词源来看, 所以很自然, 你想做得很好.

不仅仅是为了让自己从人群中脱颖而出,成为一个更好的开发者. 不仅仅是为了避免 “丹” 每日WTF而是因为您相信代码优化是正确的事情. 你为自己的工作感到自豪.

计算机硬件越来越快,而且 软件。 更容易做,但不管你做什么简单的事情 只是想要能够做,该死的 总是比上一个花更长的时间. 你对这种现象(顺便说一句)摇头, 即沃斯定律),并决心扭转这一趋势.

你很高尚,但别说了.

就停止!

你很有可能无法实现自己的目标, 不管你在编程方面多么有经验.

怎么这么? 让我们回顾一下.

首先,什么 is 代码优化?

通常,当我们定义它时,我们假设我们希望代码 执行 更好的. 我们说代码优化是编写或重写代码,使程序使用尽可能少的内存或磁盘空间, 最小化其CPU时间或网络带宽, 或者充分利用额外的核心.

在实践中,我们有时默认使用另一种定义:编写更少的代码.

但是,你为了这个目标而编写的先发制人的坏代码更有可能成为某人的眼中钉. 谁的? 下一个不得不理解你的代码的倒霉的人,甚至可能是你自己. 一个聪明能干的人, 像你这样的, 保持你的目标高尚,但重新评估你的手段, 尽管它们看起来毫无疑问是凭直觉的.

代码高尔夫:+197%,性能:-398%,简单性:-9999%

所以代码优化是一个模糊的术语. 这是在我们考虑其他一些优化代码的方法之前, 下面我们会讲到.

让我们从听取圣人的建议开始,一起探索 杰克逊著名的代码优化规则:

  1. 不要这样做.
  2. (仅限专家使用)!) 不要这样做 然而,.

1. 不要这样做:引导完美主义

我将从一个非常尴尬的极端例子开始, 很久以前, 我刚刚开始涉足SQL这个美妙的、鱼与熊掌兼得的世界. 问题是, 然后我踩在蛋糕上,不想再吃了,因为它是湿的,开始闻起来像脚.

我刚刚开始涉足SQL这个美妙的、鱼与熊掌兼得的世界. 问题是,然后我踩到了蛋糕……

等待. 让我从刚才的比喻中退出来解释一下.

我在做R&D表示内部网应用程序, 我希望有一天它能成为我工作的小公司的一个完全集成的管理系统. 它会为他们追踪一切, 而且不像他们当时的制度, 它永远不会丢失他们的数据, 因为它将由RDBMS支持, 而不是其他开发人员使用的那种自产的平面文件. 我想从一开始就把所有东西设计得尽可能聪明,因为我有一张空白的石板. 关于这个系统的想法像烟花一样在我的脑海中爆炸, 我开始为CRM设计表格联系人和他们的许多上下文变化, 会计模块, 库存, 采购, CMS, 项目管理, 我很快就会拿它当狗食.

这一切戛然而止,发展—— 性能方面,因为…你猜对了,优化.

我看到对象(表示为表行)在现实世界中彼此之间可能有许多不同的关系,并且我们可以从跟踪这些关系中获益:我们将保留更多的信息,并最终可以在所有地方自动化业务分析. 把这看作是一个工程问题, 我做了一些看起来像是优化系统灵活性的事情.

此时此刻, 注意你的脸很重要, 因为如果你的手心受伤了,我是不会负责的. 准备好了? 我创建了两个表: 的关系 它有一个外键引用, 的关系_type. 的关系 可以在整个数据库的任何地方引用任意两行, 并描述它们之间关系的本质.

数据库表:employee、公司、的关系、的关系_type

哦,男人. 我刚刚优化了这种灵活性 太多了.

事实上,太多了. 现在我有了一个新问题:给定 的关系_type 在每个给定的行组合之间自然没有意义吗. 虽然这可能说得通 有一个 受雇于 与a的关系 公司,这在语义上永远不可能等同于两个之间的关系 文档s.

好的,没问题. 我们把两列相加 的关系_type,指定此关系可以应用于哪些表. (如果您猜到我想通过将这两列移动到引用的新表中来对其进行规范化,那么这里就有好处了 的关系_type.id,这样的关系 可以 如果在语义上应用于一对以上的表,则表名不会重复. 毕竟, 如果我需要更改表名,而忘记在所有适用的行中更新它, 这可能会造成bug! 回想起来,至少昆虫可以为栖息在我头骨里的蜘蛛提供食物.)

数据库表:的关系_type和applicable_to, 以及由箭头表示的的关系_type的两列的复杂数据

谢天谢地,在沿着这条路走得太远之前,我在一场线索棒风暴中被打昏了. 当我醒来, 我意识到我已经做到了,或多或少, 重新实现RDBMS的内部外键相关表. 通常情况下,我很享受这样的时刻:在结束时,我趾高气扬地宣称:“我太超了。,但是这个, 不幸的是, 不是他们中的一个. 忘记 未能扩大规模-这种设计的可怕膨胀使得我的应用程序的后端仍然很简单, 谁的数据库几乎没有填充任何测试数据, 几乎不能用.

用外钥匙,卢克!

让我们回过头来看看其中的两个参数. 一个是灵活性,这是我的既定目标. 在这种情况下,我的优化,本质上是架构的,甚至不是不成熟的:

代码优化步骤:架构是程序优化的第一部分

(我们将在我最近发表的文章中详细介绍, 如何避免过早优化的诅咒.)尽管如此,我的解决方案还是失败了,因为距离太远了 灵活的. 另一个指标,可扩展性,是我甚至没有考虑到的,但我设法破坏了它 至少同样壮观 附带损害.

没错,“哦.”

双面膜,当一个面膜不够用的时候

这对我来说是一个强有力的教训,告诉我优化是如何完全出错的. 我的完美主义彻底崩溃了:我的聪明导致我提出了我所做过的最不聪明的解决方案之一.

优化你的习惯,而不是代码

当您发现自己在拥有工作原型和测试套件以证明其正确性之前就倾向于重构时, 考虑一下你还可以在哪里引导这种冲动. 数独和门萨都很棒, 但也许对你的项目有直接好处的东西会更好:

  1. 安全
  2. 运行时的稳定性
  3. 清晰度和风格
  4. 编码效率
  5. 测试效果
  6. 分析
  7. 你的工具箱/德
  8. DRY(不要重复自己的话)

但要注意:优化其中任何一个都是以牺牲其他的为代价的. 至少,它是以时间为代价的.

这里很容易看出编写代码是一门多么高超的艺术. 对于以上任何一项, 我可以告诉你太多或太少是如何被认为是错误的选择. 谁在思考,这也是上下文的重要组成部分.

例如, 关于DRY:在我的一份工作中, 我继承了一个至少80%是冗余语句的代码库, 因为它的作者显然不知道如何以及何时编写函数. 另外20%的代码是令人困惑的自相似.

我的任务是给它添加一些功能. 其中一个特性需要在所有要实现的代码中重复出现, 任何未来的代码都必须小心 copypasta会 来利用新特性.

很明显, 它需要重构,只是为了我自己的理智(高价值)和任何未来的开发人员. 但, 因为我是代码库的新手, 我首先编写了测试,这样我就可以确保我的重构没有引入任何回归. 事实上, 他们就是这么做的:我在这个过程中发现了两个错误,在脚本产生的所有冗长的输出中,我没有注意到这些错误.

最后,我认为我做得很好. 重构之后, I impressed my boss with having implemented what had been 考虑ed a difficult feature with a few simple lines of code; moreover, 总的来说,代码的性能提高了一个数量级. 但没过多久,那个老板又说我做事太慢了, 这个项目应该已经完成了. 翻译:编码效率是一个更高的优先级.

注意:任何特定方面的优化都是以牺牲其他方面为代价的. 至少,它是以时间为代价的.

我仍然认为我的选择是正确的, 即使当时我的老板没有直接欣赏代码优化. 如果没有重构和测试,我认为需要更长的时间才能真正得到正确的I.e.,专注于编码速度实际上会阻碍它. 嘿,这就是我们的主题!)

将此与我在一个小项目中所做的一些工作进行对比. 在项目中, 我在尝试一个新的模板引擎, 从一开始就想养成好习惯, 尽管尝试新的模板引擎并不是该项目的最终目标.

当我注意到我添加的几个块彼此非常相似时, 而且, 每个块需要引用同一变量三次, DRY的铃声在我脑中响起, 我开始寻找正确的方法来做我试图用这个模板引擎做的事情.

事实证明, 经过几个小时毫无结果的调试, 这在我想象的模板引擎中是不可能实现的. 不仅没有 完美的 DRY solution; there wasn’t 任何 DRY解决方案!

试着优化我的这个值, 我完全脱离了我的编码效率和我的快乐, 因为这次绕道让我的项目失去了那天本可以取得的进展.

即便如此,我也完全错了? 有时候,做点投资是值得的, 尤其是在新的科技背景下, 尽早了解最佳实践. 需要重写的代码更少,需要改掉的坏习惯也更少?

No, 我认为即使是寻找一种方法来减少代码中的重复也是不明智的——这与我在前面的轶事中的态度形成鲜明对比. 原因在于环境决定一切:我当时正在一个小型游戏项目中探索一项新技术, 没有长期安定下来. 一些额外的台词和重复不会伤害任何人, 但注意力的分散伤害了我和我的项目.

等等,所以寻求最佳实践可能是一个坏习惯? 有时. 如果我的 main 目标是学习新引擎, 或者一般的学习, 那么这段时间应该是花在修修补补上的, 寻找极限, 通过研究发现不相关的特征和陷阱. 但我忘记了这不是我的主要目标,这让我付出了代价.

就像我说的,这是门艺术. 和 艺术的发展 受益于提醒, 不要这样做. 它至少能让你考虑到在你工作时哪些价值观在起作用, 哪些是最重要的 in 你的 上下文.

那第二条规则呢? 我们能优化吗??

2. 不要这样做 然而,已经有人这么做了

OK, 不管是你还是别人, 你发现你的架构已经设置好了, 数据流已经被考虑并记录下来, 是时候编写代码了.

让我们来 先别这么做 更进一步: 甚至还不需要编写代码.

这本身可能听起来像是过早的优化,但这是一个重要的例外. 为什么? 为了避免可怕的NIHS, 或者“非本发明”综合症——假设您的优先级包括代码性能和最小化开发时间. 如果不是,如果你的目标完全是学习型的,你可以跳过下一部分.

虽然有可能人们 重新发明方轮 完全是出于狂妄自大, 我相信诚实, 卑微的人, 就像你和我, 仅仅因为不知道所有的选择就会犯这个错误吗. 了解堆栈中每个API和工具的每个选项,并在它们成长和发展时保持领先,这当然是一项艰巨的工作.

但, 投入这段时间会让你成为一名专家,并使你不会成为CodeSOD上第无数个被诅咒和嘲笑的人,因为他们对日期时间计算器或字符串操纵器的着迷留下了毁灭性的痕迹.

(与这种通用模式相对应的是旧的Java 日历 API,但是 现在已经修好了.)

检查你的标准库, 检查框架的生态系统, 检查已经解决你问题的自由/开源软件

机会是, 您正在处理的概念都有非常标准和众所周知的名称, 因此,快速上网搜索将为你节省大量时间.

举个例子,我最近正准备分析一款桌面游戏的AI策略. 一天早上醒来,我意识到,如果我只是简单地使用我记得的某个组合概念,我正在计划的分析可以效率提高几个数量级. 我现在对这个概念的算法不感兴趣, 我已经知道要搜索的正确名字了. 然而, 经过大约50分钟的研究和尝试一些初步代码后,我发现了这一点, 我没有设法将我发现的半成品伪代码转化为正确的实现. (你能相信有一篇博客文章,作者假设了错误的算法输出吗, 错误地实现算法以匹配假设, 评论者指出了这一点, 几年后, 它还没有修好?)这时,我的早茶开始起作用了,我开始寻找 【欧博体育app下载】【欧博体育app下载】. 30秒后, 我从GitHub上得到了可以证明的正确代码,并继续做我真正想做的事情. 只是说得具体点,包括语言, 而不是假设我必须自己实现它, 意味着一切.

是时候设计你的数据结构和实现你的算法了

再说一遍,不要玩 代码高尔夫. 在实际项目中优先考虑正确性和清晰度.

时间投入:10小时,执行时间:+25%,内存使用:+3%,混乱:100%

OK, 所以你已经看过了, 你的工具链中没有现成的解决问题的工具, 或者在网络上自由授权. 你可以推出自己的.

没有问题. 建议很简单,顺序如下:

  1. 将其设计成能够简单地向新手程序员解释.
  2. 编写一个符合该设计产生的期望的测试.
  3. 编写代码时,新手程序员可以很容易地从中获得设计.

很简单,但可能很难理解. 这就是编码习惯和 代码味道 艺术和 工艺 优雅也开始发挥作用. 显然,你在这一点上所做的是一个工程方面,但再次强调,不要玩 代码高尔夫. 在实际项目中优先考虑正确性和清晰度.

如果你喜欢视频, 这是一个遵循上述步骤的人,或多或少. 对于不喜欢视频的人,我总结一下:这是一场谷歌求职面试中的算法编码测试. 被采访者首先以一种易于沟通的方式设计算法. 在编写任何代码之前,有一些工作设计期望的输出示例. 然后代码自然就会出现.

至于测试本身,我知道在某些圈子里,测试驱动的开发是有争议的. 我认为部分原因是它可能会被过度使用, 虔诚地追求,以至于牺牲了开发时间. (再一次, 从一开始就试图过多地优化一个变量,这是在搬起石头砸自己的脚.) 甚至Kent Beck也没有将TDD发挥到如此极端的程度他发明了极限编程,并写了一本关于TDD的书. 因此,从简单的事情开始,以确保您的输出是正确的. 毕竟,无论如何,您都要在编码后手动执行该操作,对吗? (如果你是这样一个摇滚明星程序员,你甚至不运行你的代码后,第一次编写. 在这种情况下, 也许您会考虑将测试留给代码的未来维护者,以便了解这一点 他们 不会破坏你出色的实现.)所以与其做手册, 视觉差异, 有了测试,你已经让计算机为你做了这些工作.

在实现算法和数据结构的相当机械的过程中, 避免逐行优化, 甚至不要 认为 使用自定义的低级语言外部(汇编),如果你用C编程, 如果你在用Perl编程的话, 等.在这一点上. 原因很简单:如果您的算法完全被替换了——直到过程的后期才会发现是否需要这样做——那么您的低级优化工作最终将没有任何效果.

一个ECMAScript示例

On 优秀的社区代码审查网站练习.io,我最近发现 一个练习 这明确建议尝试优化重复数据删除或清晰度. 我针对重复数据删除进行了优化, 只是为了展示如果你采用dry——一种有益的编码心态——事情会变得多么荒谬, 正如我上面提到的,太远了. 下面是我的代码:

const zeroPhrase = "No more";
const wallPhrase = " on the wall";
const st和ardizeNumber = number => {
   If (number === 0) { return zeroPhrase; }
   返回“+ number;
}
const 瓶Phrase = number => {
   const possibilities = (number === 1) ? '' : 's';
   返回标准编号(number) +“瓶”+可能性+“啤酒”;
}
导出默认类Beer {
   静态诗句(数字){
       const nextNumber = (number === 0) ? 99:(数字- 1);
       const thisBottlePhrase = 瓶Phrase(number);
       const nextBottlePhrase = 瓶Phrase(nextNumber);
       let phrase = thisBottlePhrase + wallPhrase + ", " + thisBottlePhrase.toLowerCase() + ".\n";
       If (number === 0) {
           短语+=“去商店再买一些”;
       } else {
           const 瓶rreference = (number === 1) ? “it”:“one”;
           短语+=“Take”+ 瓶rreference +“down 和 pass it around”;
       }
       返回短语+“,”+ nextBottlePhrase.toLowerCase() + wallPhrase + ".\n";
   }
   静态歌唱(开始= 99,结束= 0){
       返回数组.from(Array(start - end + 1)).键()).map(offset => {
           返回这.诗句(开始-偏移);
       }).加入(' \ n ');
   }
}

几乎没有任何字符串的重复! 通过这种方式编写,我手动实现了啤酒歌(但是)的文本压缩形式 只有 为了啤酒之歌). 到底有什么好处? 好吧,假设你想唱关于用罐头而不是瓶子喝啤酒的歌. 我可以通过改变来做到这一点 单个实例 of to 可以.

不错的!

,对吧?

不行,因为那样所有的测试都会中断. 这很容易修复,我们只需要搜索并替换 在单元测试规范中. 这和一开始对代码本身做同样的事情是很容易做到的,并且有同样的意外破坏的风险.

同时,我的变量之后会被奇怪地命名,比如 瓶Phrase 没有任何关系 在所有. 避免这种情况的唯一方法是准确地预见将要进行的更改类型,并使用更通用的术语,如 or 容器 代替 在变量名中.

以这种方式为未来做准备的智慧是相当值得怀疑的. 你想要改变任何事情的几率有多大? 如果你这样做了,你所做的改变会如此方便吗? 在 瓶Phrase 例如,如果你想本地化成一种语言 有两个以上的复数形式? 没错,重构时间长了,代码可能看起来更糟.

但是当你的要求 do 改变,你不只是试图预测它们, 然后 也许是时候进行重构了. 或者你仍然可以推迟:你将添加多少船舶类型或本地化, 实际? 无论如何,当您需要平衡重复数据删除和清晰度时,这是非常值得关注的 这是卡特里娜·欧文的演示.

回到我自己的丑陋的例子:不用说, 在这里,重复数据删除的好处甚至没有被充分认识到. 同时,它的成本是多少?

除了一开始花更长的时间来写, 现在读起来就不那么琐碎了, 调试, 和维护. 想象一下允许适度重复的可读性水平. 例如, 有四个韵文变体的.

但我们还没有优化!

现在你的算法已经实现了, 你已经证明了它的输出是正确的, 祝贺你! 你有一个基线!

最后,是时候进行优化了? 不,仍然 先别这么做. 是时候拿起你的基准线,做一个漂亮的 基准. 为您的期望设置一个阈值,并将其放在您的测试套件中. 然后,如果有什么东西突然使代码变慢了——即使它仍然可以工作——您将在它发布之前知道.

还是先不要优化, 直到你实现了完整的相关用户体验. 在此之前,您可能针对的是与您需要的完全不同的代码部分.

完成你的应用(或组件), 如果你还没有, 设置你所有的算法基准.

一旦完成, 这是创建端到端测试并对其进行基准测试的好时机,这些测试涵盖了您的系统最常见的实际使用场景.

也许你会发现一切都很好.

或者你已经决定了, 在现实生活中, 某些东西太慢或占用太多内存.

OK, 现在 你可以优化

只有一种方法能客观地看待它. 是时候突破了 火焰图 以及其他分析工具. 经验丰富的工程师可能比新手猜得更好,也可能没有, 但这不是重点:唯一确定的方法就是侧写. 在优化代码以获得性能的过程中,这总是要做的第一件事.

您可以在给定的端到端测试期间进行分析,以获得真正产生最大影响的内容. (后来, 部署后, 监视使用模式是一种很好的方法,可以帮助您了解系统的哪些方面与将来的度量最相关.)

请注意,您并没有试图充分使用剖析器——您更多地是在寻找函数级剖析,而不是语句级剖析, 一般, 因为此时你的目标只是找出答案 这算法 就是瓶颈.

现在您已经使用分析来识别系统的瓶颈, 现在你可以尝试优化了, 确信你的优化是值得做的. 您还可以证明您的尝试是多么有效(或无效), 感谢你一路走来所做的那些基准测试.

整体技术

首先,记住尽可能长时间保持高水平:

在整个算法层面上,一种技术是 强度降低. 但是,在减少循环到公式的情况下,要注意留下注释. 不是每个人都知道或记住每一个组合公式. 也, 小心你对数学的使用:有时候你认为可能是力量减少的东西并不是, 最后. 例如,我们假设 X * (y + z) 有明确的算法含义吗. 如果你的大脑在某种程度上受过训练, 不管出于什么原因, 自动取消类似术语的分组, 你可能会想把它写成 X * y + X * z. 一方面, 这在读者和清晰的算法含义之间设置了一个障碍. (更糟糕的是,现在实际上 高效是因为需要额外的乘法运算. 就像开环把裤子弄糊了一样.)无论如何, 简短地说明一下你的意图会大有帮助, 甚至可以帮助你在犯错误之前发现自己的错误.

不管你是用一个公式还是用另一个基于循环的算法替换一个基于循环的算法, 你已经准备好测量差异了.

但也许仅仅通过改变数据结构就能获得更好的性能. 让自己了解需要对正在使用的结构执行的各种操作之间的性能差异, 在任何替代方案上. 也许在您的上下文中,散列看起来有点混乱, 但是比起一个数组来,这种优越的搜索时间值得吗? 这些都是由你来决定的取舍.

您可能会注意到,这归结为当您调用便利函数时,知道哪些算法正在代表您执行. 所以说到底,这和强度降低是一样的. 了解供应商的库在幕后做了什么不仅对性能很重要,而且 也是为了避免无意的bug.

优化

OK, 系统的功能完成了, 但从用户体验的角度来看, 性能还可以进一步微调. 假设你已经做了所有你能做的,是时候 考虑 到目前为止我们一直在避免的优化. 考虑, 因为这种级别的优化仍然是对清晰度和可维护性的权衡. 但你已经决定是时候了, 因此,请继续执行语句级分析, 现在你处于整个系统的环境中, 真正重要的地方.

就像您使用的库一样, 在编译器或解释器级别上,为了您的利益,已经投入了无数的工程时间. (毕竟,编译器优化和代码生成 它们都是自己的大话题). 这甚至是真的 在处理器级别. 尝试优化代码 意识到底层发生了什么 是不是认为四轮驱动意味着你的车也能更容易停车.

除此之外,很难给出好的通用建议,因为这真的取决于你的技术堆栈和你的分析器所指向的内容. 但, 因为你在测量, 你已经处于寻求帮助的绝佳位置, 如果解决方案不能从问题环境中有机地、直观地呈现给您. (睡眠和思考其他事情的时间也会有所帮助.)

在这一点上,根据上下文和扩展需求,Jeff Atwood可能会建议 简单地添加硬件,这比开发人员的时间更便宜.

也许你不走那条路. 在这种情况下,它可能有助于探索各种类别的 代码优化 技术:

更具体地说:

无论如何,我 do 再吃点 不该做的事 对你:

不要将一个变量用于多个不同的目的. 就可维护性而言,这就像没有油的汽车一样. 只有在最极端的嵌入式情况下,这才有意义, 即使在这些情况下, 我认为现在已经不是了. 这是编译器的工作. 你自己做,然后移动一行代码,你就引入了一个bug. 保存记忆的幻觉对你来说值得吗?

不知道为什么不要使用宏和内联函数. 是的,函数调用开销是一种成本. 但是避免它通常会使您的代码更难调试,有时实际上会使它变慢. 到处使用这种技术只是因为它偶尔是个好主意,这是一个例子 金锤.

不要用手展开. 再一次,这种形式 循环优化 总是有更好的东西吗 通过编译等自动化过程进行优化,而不是牺牲代码的可读性.

在最后两个代码优化示例中具有讽刺意味的是,它们实际上可能是反性能的. 当然,由于您正在进行基准测试,您可以为您的特定代码证明或否定这一点. 但即使你看到了性能的提高, 回到艺术方面, 看看在可读性和可维护性上的损失是否值得.

这是你的:最优优化优化

尝试性能优化可能是有益的. 通常, 虽然, 这件事做得太早了, 它会带来一连串的副作用, 最讽刺的是, 导致性能变差. 我希望你们对优化的艺术和科学有了更广泛的了解, 最重要的是, 适当的语境.

如果这有助于我们摆脱从一开始就编写完美代码的观念,而是编写正确的代码,我很高兴. 我们必须记住从上到下进行优化, 证明瓶颈在哪里, 并在修复前后进行测量. 这是优化优化的最优策略. 祝你好运.

了解基本知识

  • 什么是软件优化?

    软件优化可以指一个软件的许多方面, 比如灵活性, 可维护性, 或性能. 然而,性能通常是隐含的.

  • 什么是性能优化?

    甚至性能优化也可以涉及代码的许多不同方面. 有时候,各个方面之间甚至可能存在内在的矛盾,比如磁盘大小与CPU时间. 最小化运行时间是最常见的目标.

  • 什么是循环优化?

    循环优化是在不改变输出的情况下,以提高性能的方式转换循环. 因为许多转换是以可维护性和可读性为代价的, 通常这最好留给编译器.

  • 当我们过早地优化性能时,通常会有哪些风险?

    正确性, 清晰, 可维护性, 灵活性, 和, 具有讽刺意味的是, 甚至是正在优化的特定方面(内存使用), 响应时间, 等.). 更具讽刺意味的是:当被优化的代码被内置或第三方函数取代时,从一开始就进行优化并没有节省任何时间.

  • 在编写代码之前要采取哪些代码优化步骤?

    首先优化架构, 然后(如果你自己实现的话)算法和数据结构.

  • 在已有代码上使用的代码优化步骤是什么,甚至专家也需要遵循这些步骤?

    首先,概要文件. 即使是专家也经常错误地识别需要优化的内容. 在那之后, 正确的步骤是基础科学:在做出改变之前和之后仔细考虑基准. 没有正确的背景和度量, 优化是在一屋子好朋友面前瞎猜的!

就这一主题咨询作者或专家.
预约电话
凯文·布洛赫的头像
凯文·布洛赫
验证专家 in 工程

位于 Bergerac、法国

成员自 2017年1月31日

作者简介

Kevin拥有超过20年的全栈、桌面和独立游戏开发经验. 他最近专门研究PostgreSQL、JavaScript、Perl和Haxe.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

专业知识

工作经验

8

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® 社区.