为什么过早优化如此糟糕?


168

在对优化进行了一点研究之后,我发现(几乎在所有地方)过早优化游戏似乎是普遍公认的罪过。

我真的不明白这一点,在最后改变游戏的某些核心结构,而不是在第一次考虑性能的情况下开发它们,是否会变得异常困难?

我得到等待,直到游戏结束,它会告诉您是否甚至需要优化,但是您还是不应该这样做,毕竟,它可以扩大游戏可以运行的设备的种类,从而增加潜在的数量玩家。

有人可以向我解释为什么过早优化是一个坏主意吗?


评论不作进一步讨论;此对话已转移至聊天
乔什

3
回答这个问题再简单不过了:“浪费时间”。您还可能会问“为什么要在购物时省钱?”
Fattie

27
相反,请注意,许多工程师只是简单地说“不要太早优化”这句话是错误的。简单地说,该句子应该是“在知道要优化的内容之前不要进行优化”。因此,很简单,如果存在三个系统A,B和C,那么如果A根本不是瓶颈,而C实际上是瓶颈,那么对A进行完全毫无意义的优化。在该示例中,显然,优化A会完全浪费时间。所以-很简单-不优化,直到你知道一个的,BC优化:这一切都意味着,就这么简单。
Fattie

2
在开发过程中优化应用程序的时间等级与尝试将一些指令从循环中删除通常是恒定的时间有很大不同。关注O(n)vs O(n log n),而不是“以这种方式编写for循环可以节省一条CPU指令”。

1
@phyrfox实际上,减少加载时间对我来说似乎更令人印象深刻。三秒钟的加载时间非常明显。我不确定55fps至60fps是否引人注目。
immibis

Answers:


237

前言:

评论中提出了一些反对意见,我认为这很大程度上是由于人们对我们所说的“过早优化”的含义的误解-因此,我想对此进行一点澄清。

“不要过早优化”并不能意味着“你知道写代码是错误的,因为高德纳说你不准把它清理干净,直到最后”

这意味着“除非您知道程序的哪些部分实际上需要更快的帮助,否则就不要牺牲时间和可读性来进行优化。” 由于典型的程序将大部分时间都花在了几个瓶颈上,因此投资优化“所有内容”可能不会像将相同的投资仅集中在瓶颈的代码上那样获得同样的速度提升。

这意味着,如果有疑问,我们应该:

  • 首选易于编写,易于理解且易于修改的代码

  • 检查是否需要进一步优化(通常通过对运行的程序进行概要分析,尽管下面的注释说明了进行数学分析的唯一风险-您还需要检查数学是否正确)

过早的优化不是

  • 以适合您需求的方式构造代码的架构决策-以经过考虑的方式选择适当的模块/职责/接口/通信系统。

  • 简单高效,无需花费额外时间或使您的代码难以阅读。诸如使用强类型输入之类的东西可以既高效又可以使您的意图更加清晰。缓存引用而不是重复搜索是另一个示例(只要您的案例不需要复杂的缓存无效逻辑-可能要等到您首先介绍简单方法后再进行编写)。

  • 为工作使用正确的算法。与穷举搜索寻路图相比,A *更优化,更复杂。这也是一个行业标准。重复主题,坚持这样的久经考验的方法实际上比使代码简单而不符合已知的最佳实践,可以使您的代码更容易理解。如果您有遇到在以前的项目中以一种方式实现游戏功能X的瓶颈的经验,则无需在该项目上再次遇到相同的瓶颈即可知道它是真实的-您可以并且应该重复使用过去有效的解决方案游戏。

所有这些优化类型都是合理的,通常不会被标记为“过早”(除非您不愿为8x8棋盘图实施尖端寻路...)

现在,我们将这些问题清除,以了解为什么我们可能会特别在游戏中发现此政策有用:


特别是在gamedev中,迭代速度是最宝贵的。我们经常会实施和重新实现比最终游戏要附带的想法更多的想法,以试图“找到乐趣”。

如果您能以一种简单明了的方式(也许有点天真)对机械师进行原型设计,并在第二天对其进行游戏测试,则比起花一个星期的时间首先制作出最优化的机械师而言,您处于更好的位置。尤其是如果事实证明很烂,而您最终却放弃了该功能。以一种简单的方式进行操作,以便您可以及早进行测试,可以节省大量不必要的代码优化工作。

与未经微调的代码相比,经过优化的代码通常可以更轻松地修改和尝试不同的变体,这些代码经过微调可以最佳地完成一件精确的事情,而这种代码往往很脆弱,并且难以修改而不会破坏代码,引入错误或减慢其运行速度。因此,在大多数开发过程中,保持代码简单易更改通常值得一点运行时效率低下(我们通常在高于目标规格的机器上进行开发,因此我们可以吸收开销并专注于首先获得目标体验),直到我们已经锁定了我们需要的功能,并可以优化我们现在知道很慢的零件。

是的,要在开发的后期重构项目的一部分以优化慢点可能很难。但是在整个开发过程中也会重复进行重构,因为您上个月进行的优化与自那时以来游戏的发展方向不兼容,或者在您获得更多功能和内容后正在修复的东西并不是真正的瓶颈在。

游戏既怪异又是实验性的-很难预测游戏项目及其技术需求将如何演变以及性能最严格的地方。在实践中,我们常常会担心错误的事情–在此处搜索性能问题,您会发现一个共同的主题是,开发人员被纸上的东西分散了注意力,这可能根本不是问题。

举一个具有戏剧性的例子:如果您的游戏是GPU限制的(并非罕见),那么花在超优化和线程化CPU工作上的所有时间可能根本不会带来明显的好处。所有这些开发时间本来可以用于实现和完善游戏功能,以获得更好的玩家体验。

总体而言,您花费在游戏上的大部分时间都不会花费在最终成为瓶颈的代码上。尤其是当您使用现有引擎时,渲染和物理系统中非常昂贵的内循环东西在很大程度上由您掌控。那时,您在游戏脚本中的工作基本上是保持引擎的状态-只要您不向其中扔扳手,那么您可能会在第一次构建时就表现出不错的效果。

因此,除了一点点代码卫生和预算外(例如,如果您可以轻松地重复使用它们,请不要重复搜索/构造内容,保持适度的寻路/物理查询或GPU回读等),养成永不结束的习惯-在我们知道真正的问题出在哪里之前进行优化对提高生产力有好处-避免浪费时间优化错误的东西,并使我们的代码更简单,更容易进行总体调整。


38
这里有一些关于StackOverflow的进一步讨论,强调了代码中可读性和清晰度的重要性,以及过早优化代码使代码难以理解(并易于引入错误)的危险。
DMGregory

8
我想补充一个好答案,以回应“ 最后改变游戏的某些核心结构,而不是第一次考虑性能来开发它们,是否会非常困难? ”当然,您首先要尝试提高效率。当出现两种选择时,您会选择效率更高的一种。否则,您将使用定义良好的界面尽可能模块化地编写游戏。然后,您可以更改每个模块内的机制,而无需重新构建整个代码库。
Baldrickk

1
@Baldrickk我想说这是值得分享的附加答案。(我赞成!)我的回答跳过了架构和规划的重要性,从而避免了首先产生大问题。至于Gizmo对“一般程序开发”的引用,这就是过早优化的概念所在。如上所述,错误的优化和丢失的优化一样容易成为技术负担。但是我们应该强调,我们永远不会以故意的缓慢方式来做事,只是更喜欢简单易读,直到我们能够描述和找到真正的问题
为止

1
虽然在你们这些人中我可能是最没有经验的人,但我必须说,我发现这种“万恶的过早优化根源”有点怪异。大约两年前,我试图在Unity3D中做一些事情。我写了一些LINQ查询,每个查询都使用前一个查询。我看了看我的代码,开始产生强烈的怀疑。我认为计算复杂性太可怕了。我写了一张纸,计算得出,以预期的数据大小处理这些查询将花费数小时。所以我在这里和那里添加了一些缓存。而且查询运行良好。
gaazkam

3
因此,您进行了尽职调查,并在从最初最清晰,最直观的代码更改代码之前,验证了问题是否存在。这意味着您的优化并非为时过早。;)“避免过早优化”并不意味着“编写不必要的昂贵代码”,而是为了简单,易读,易于修改,直到确定了明确的性能问题。这些评论并非用于讨论,因此如果您想进一步讨论,我们可以聊天。
DMGregory

42

注意:此答案开始时是对DMGregory答案的评论,因此不会重复他提出的非常好的观点。

“在最后改变游戏的某些核心结构,而不是在考虑性能的情况下首次开发它们,是否会变得异常困难?”

对我来说,这就是问题的症结所在。

创建原始设计时,尝试在最高效率上进行设计。这不是最优化,而是更多关于结构。

示例:
您需要创建一个过河系统。显而易见的设计是桥梁还是轮渡,那么您选择哪个呢?
答案当然取决于人行横道的大小和交通量。这不是优化,而是从适合您问题的设计开始。

呈现设计选择时,您会选择最适合您想要做的事情。

因此,可以说我们的交通量很低,因此我们决定建造两个码头并购买渡轮来处理交通。一个不错的简单实现
不幸的是,一旦启动并运行它,我们发现它看到的流量比预期的要多。我们需要优化轮渡!(因为它可行,现在建造一座桥不是一个好计划)

选项:

  • 买第二条渡轮(平行处理)
  • 将其他汽车甲板添加到渡轮上(路况压缩)
  • 升级轮渡的引擎以使其更快(重写处理算法)

在这里,您应该尝试使原始设计尽可能地模块化。
以上所有都是可能的优化,您甚至可以全部执行这三个操作。
但是,如何在不进行大的结构更改的情况下进行这些更改?

如果您具有带有明确定义的接口的模块化设计,那么实现这些更改应该很简单。
如果您的代码未紧密耦合,则对模块的更改不会影响周围的结构。

让我们来看看增加一条渡轮。
一个“坏”程序可能是围绕单个轮渡的想法构建的,并且将码头状态,轮渡状态和位置都捆绑在一起并共享状态。这将很难修改以允许将额外的渡轮添加到系统中。
更好的设计是将码头和渡轮作为单独的实体。它们之间没有紧密的耦合,但是它们有一个接口,轮渡可以到达那里,卸下乘客,接上新乘客,然后离开。码头和轮渡仅共享此接口,在这种情况下,通过添加第二条轮渡,可以轻松更改系统。码头并不在乎实际上有什么渡轮,它所关心的只是某事(任何东西)正在使用其接口。

tl; dr:

  • 首先尝试设计效率。
  • 当出现两种选择时,您会选择效率更高的一种。
  • 使用定义明确的接口,以尽可能模块化的方式编写代码。

然后,您可以在需要优化时更改每个模块内的机制,而无需重新构建整个代码库。


16
在开始时,您还可以将渡轮实现为IRiverCrossing,当很明显流量对于渡轮设置而言太大时,请将桥实现为IRiverCrossing并放下。当然,诀窍是减少渡轮的外部API和桥接到通用功能,以便它们可以由同一接口表示。
Mindor先生

2
您甚至可能为这些模块化接口编写了自动化测试,因此您可以快速进行重构,而不必担心会破坏要触摸的模块之外的任何内容。
user3067860

2
为什么OOP在当今如此重要的一个很好的例子。
Jaime Gallego'17

1
您打对了。当速度不是核心要求之一时,唐纳德·克努斯(Donald Knuth)的口头禅是正确的,而专注于优化会损害主要设计。games,在游戏中,速度通常核心,因此必须尽早将其纳入设计。OP的担忧(以及您的回答)完全合理。
Peter A. Schneider

3
@AlexandreVaillancourt而不是回答问题标题,而是尝试回答我认为是实际回答问题的关键部分的内容。也就是说,“如果我的设计是固定的,那么以后为什么要进行更多的优化工作为什么不应该提早进行优化”。这个答案也开始于对DMGregory答案的评论,并且是对它的补充,重复他的答案没有多大意义。
Baldrickk

24

“不及早优化”并不意味着“选择最糟糕的处理方式”。您仍然需要考虑性能的影响(除非您只是在制作原型)。关键不是要在开发时破坏其他更重要的事情,例如灵活性,可靠性等。选择简单,安全的优化方法-选择您要限制的事情以及您可以自由使用的事情;跟踪成本。您应该使用强类型吗?大多数游戏运行良好,并且运行良好。如果您发现Gamemplay灵活性的有趣用途,您将花费多少钱才能删除?

修改优化的代码,尤其是“智能”代码,要困难得多。始终选择它会使某些事情变得更好,而另一些事情则变得更糟(例如,您可能将CPU时间用于内存使用)。在做出选择时,您需要意识到所有的含义-它们可能是灾难性的,但也可能会有所帮助。

例如,指挥官Keen,Wolfenstein和Doom均建立在优化的渲染引擎之上。每个人都有使游戏最初存在的“技巧”(每个人还随着时间的推移开发了进一步的优化功能,但这并不重要)。这很好。充分优化游戏的核心是可以的,这种想法使游戏成为可能。尤其是当您要探索新的领域时,该特定的优化功能使您可以考虑没有太多探索的游戏设计。优化引入的限制可能也会给您带来有趣的游戏玩法(例如,RTS游戏中的单位数量限制可能已经开始作为提高性能的一种方式,但它们也具有游戏玩法效果)。

但请注意,在每个示例中,如果没有优化,游戏就不会存在。他们不是从“完全优化”的引擎开始的,而是从根本上开始,然后逐步发展。他们正在开发新技术,并使用它们来制作有趣的游戏。引擎技巧仅限于代码库的尽可能少的部分-仅在游戏玩法大部分完成时或在允许有趣的新功能出现的地方才引入较重的优化。

现在考虑您可能想要制作的游戏。真的有一些创造或打破游戏的技术奇迹吗?也许您正在设想在无限世界上进行开放世界的游戏。那真的是游戏的核心吗?没有它,游戏将无法正常工作吗?也许您正在考虑一款地形可以无限变形,具有逼真的地质学的游戏;您可以使其在较小的范围内工作吗?它可以在2D而不是3D中工作吗?尽早获得乐趣-即使优化可能需要您重做大量现有代码,这也值得;您甚至可能意识到做大事情并不能真正使游戏变得更好。

作为最近进行大量优化的游戏的示例,我将指出Factorio。传送带是游戏的关键部分-传送带成千上万条,并且它们在工厂各处都承载着许多单独的材料。游戏是从优化过的皮带引擎开始的吗?没有!实际上,最初的皮带设计几乎不可能进行优化-对皮带上的物品进行物理模拟,从而创建了一些您可以做的有趣的事情(这是获得“紧急”游戏的方式-令人惊讶的游戏方式设计师),但是这意味着您必须模拟皮带上的每个项目。有了成千上万个皮带,您就可以得到数以万计的物理模拟物品-即使只是将其卸下并让皮带完成工作,也可以使相关的CPU时间减少95-99%,即使不考虑内存局部性。但是,只有在实际达到这些限制时,这样做才有用。

与皮带有关的几乎所有东西都必须重新制作,以使皮带得到优化。而且需要优化皮带,因为大型工厂需要大量皮带,而大型工厂是游戏的吸引力之一。毕竟,如果您不能拥有大型工厂,那么为什么会有一个无限的世界?有趣的是,您应该问-早期版本没有 :)游戏经过多次重新设计和重塑,以达到现在的状态-包括当他们意识到Java不是开发Java的必经之路时,进行100%彻底的重制。像这样的游戏并切换到C ++。它对Factorio很好用(尽管这仍然是一件好事,但从一开始就没有对其进行优化-特别是因为这是一个业余项目,否则可能会因为缺乏兴趣而失败)。

但事实是,有有限范围的工厂可以做很多事情-许多游戏都表明了这一点。极限比自由更能赋予人们乐趣。如果“地图”是无限的,Spacechem会更有趣吗?如果您从高度优化的“皮带”开始,那么您将被迫采取这种方式。而且您无法探索其他设计方向(例如查看使用物理模拟的传送带可以做的有趣的事情)。您正在限制潜在的设计空间。似乎不是这样,因为您看不到很多未完成的游戏,但是困难的部分是正确获得乐趣-对于您看到的每个有趣的游戏,可能有数百个游戏无法到达那里并被废弃(或更糟的是,以可怕的混乱状态发布)。如果优化可以帮助您做到这一点-请继续。如果没有... 这可能为时过早。如果您认为某些游戏机制效果不错,但需要进行优化才能真正发挥作用-请继续。如果您没有有趣的机制,不要优化他们。首先找到乐趣-您会发现大多数优化都无济于事,而且常常是不利的。

最后,您将获得一个很棒的有趣游戏。现在进行优化有意义吗?哈!仍然没有您想象的那么清楚。有什么好玩的你可以代替吗?不要忘记您的时间仍然有限。一切都需要付出努力,而您想将精力集中在最重要的地方。是的,即使您正在制作“免费游戏”或“开源”游戏。观看游戏的玩法;注意性能成为瓶颈。优化这些地方是否会带来更多乐趣(例如建造更大,更纠结的工厂)?它是否可以吸引更多玩家(例如,在性能较弱的计算机上或在不同的平台上)?您始终需要确定优先级-寻找产出率。您可能会发现,仅从玩游戏和观看其他人玩游戏中就可以找到很多低落的果实。但是请注意重要的部分-要到达那里,您需要游戏。集中精力。

作为最佳选择,请考虑优化永无止境。您完成并转移到其他任务并不是一个带有少许勾号的任务。您总是可以进行“更多优化”,并且任何开发的很大一部分都是要了解优先级。您不是出于优化目的而进行优化-这样做是为了实现特定的目标(例如,“在333 MHz奔腾上同时显示200个单位”是一个很好的目标)。不要仅仅因为您过多地专注于中间目标而无法跟踪最终目标,而中间目标甚至可能不再是最终目标的先决条件。


我相信factorio开发人员现在正在重新优化皮带以便他们只需要定期模拟物品,而在其他所有时间,它只是在您查看物品时对其位置进行插值。但是,他们才刚刚这样做,现在当整个游戏进行了有效的根据各地带(或机器人)很长一段时间,并直到人们开始注意和抱怨的性能。
immibis

2
@immibis正是。在人们真正达到极限之前使其性能更好将浪费资源,而这些资源最好用于其他地方。即使进行了最新的优化,您也很可能仅在超大型工厂中遇到了超出正常游戏范围(发射火箭)的问题。但是它启用了新的Marathon游戏设置,这需要大量的后勤工作。再者,他们通过从实际玩游戏的人那里获得统计信息来识别瓶颈-大约一半的瓶颈对他们来说是一个很大的惊喜。
Lu安

@Fattie所以您了解问题,但不了解答案?您是否只是想说一个更简单的答案是可能的(例如“经济学”)?我不认为您的评论应该具有建设性。
a安

2
@Fattie如果您认为答案是“只有在知道了瓶颈之后才进行优化”,然后将其发布为答案。您已经花了比需要一个好的答案更多的单词,所以继续吧。哪种优化不会使事情变得更好或更坏?我当然从未见过。我一直重申的基本观点是,这始终是一个折衷方案-时间可能会在其他地方花费得更好,复杂性限制了您的灵活性...这些示例指出,“早期”不是绝对术语;从第一天开始就必须进行一些优化,而另一些则是不利的。
a安

1
@Fattie“只有在知道瓶颈后才进行优化”是“我应该何时优化?”的答案。并不能回答“为什么过早优化如此糟糕?”。
immibis

10

许多答案似乎都集中在“优化”的性能方面,而我本人也希望从更抽象的角度着眼于优化以及过早进行优化的整个过程。

当我尝试在多氨基酸的帮助下阐述自己的观点时,请为我幽默。

假设我们使用的框架或引擎设置了一些固定的边界。

在此处输入图片说明

然后,我们像这样继续创建游戏的第一层/模块。

在此处输入图片说明

继续前进,我们构建了第二层/模块。

在此处输入图片说明

在这一点上,我们可能会注意到两个模块之间有一些空间,我们可能会尝试对其进行优化以充分利用分配给我们的边界。

在此处输入图片说明

完美,现在该应用程序正在充分利用我们可用的资源,该应用程序更好,对吧?

我们继续构建应用程序的第三层/模块,然后突然意识到(也许甚至在最初的计划中我们无法预见的)第三层/模块对我们不起作用。

我们寻找一个替代方案,找到一个替代方案,最后,这还要求我们更改应用程序的第二个模块,因为它与新选择的第三个模块不兼容。(非常感谢它与我们的第一个模块兼容,因此我们不必从头开始重写所有内容。)

所以我们把它们放在一起...

在此处输入图片说明

嗯,你能看到发生了什么吗?

通过过早地优化,我们现在实际上使事情变得更糟,因为我们所针对的不是最终的结果。

而且,如果我们以后想添加一些其他模块或额外的花絮,那么此时我们可能不再具有执行这些操作的能力。

在此处输入图片说明

调整我们系统的最低级别已不再可行,因为它已被埋在所有其他层之下。

但是,如果我们选择等待我们立即对其进行优化的冲动,那么最终结果将是这样的:

在此处输入图片说明

现在,如果我们在这一点上进行优化,我们将得到满意的结果。

在此处输入图片说明

希望至少你们中的一些人阅读本书的乐趣与我阅读本书的乐趣一样:),如果您现在觉得自己对这个主题有了更好的了解,那就更好了。


3
我正在移除广告。我们不在乎您如何制作图像;唯一重要的部分是假设您有权发布它们。
Gnemlock '17

2
@Gnemlock足够公平,尽管我的意图不是针对广告,但我也可以看到它可能会被如此容易地误解,并且我同意它不会在答案中添加任何内容,因此它没有位置。
壁虎天花板

2
我认为这种视觉隐喻非常有效。回答问题的好方法!:)
DMGregory

8

钱。

归结为这一点。钱。由于时间就是金钱*,因此您在无法保证产生更多金钱的活动上花费的时间越多(即您不能将这些活动视为投资)),您浪费的金钱就越多,您赚到的钱就越少游戏。

以下是过早优化的一些潜在副作用,以及应避免进行优化的原因:

  • 您的同事讨厌您,因为您在玩玩具时会在沙盒中玩耍,而他们却在努力获取功能。
  • 延迟使高层管理人员感到不快,并使团队错过交付日期,这导致游戏在春​​季而不是在假日季节之前发布,从而导致游戏销售不足。因此,总部决定关闭工作室,有效地使您失业。没有工作就意味着没有钱。(而且由于没有人喜欢您,因为您花了太多时间进行早期优化,所以没有人希望在LinkedIn上对您的工作发表正面评价,这将使您长期处于亏损状态。)

*其他答案已充分突出了“时间”部分


作为附带说明,通常,经验有助于确定什么是过早优化,什么不是过早优化,什么对企业有价值,哪些不对企业有价值。

例如,如果您从事游戏A,并在项目结束时意识到XYZ功能在您的游戏循环中特别繁重,那么您最终就开始研究具有完全相同功能的游戏B,从而决定重写功能,并从一开始就优化它是不是真的过早的优化,因为你知道这将是一个瓶颈,如果不采取任何措施。


1
@JBentley是一个有效的观点。但是,对于“为什么”有相应的答案,这是所收集经验的直接含义。因此,1)尽早优化可能会浪费时间,而不会浪费部分时间影响平均运行时间(根据经验,您应该知道哪些代码结构适合进行最佳化最佳实践)2)尽早优化可能会使代码更难由于对某些系统施加的设计限制而需要维护。因此,您可能获得的收益太少,以换取更长的开发周期/需要维护的繁琐代码。
teodron

3
@JBentley将此视为DMGregory答案的附录。
亚历山大瓦尔兰科特

1
这似乎是这里唯一有价值的答案。问题是重言式。您可能还会问:“为什么,实际上,您想要一款游戏在应用商店上赚更多而不是少赚多少钱?” 你怎么回答呢?
Fattie

@Fattie在回答中有这种观点是很好的。但是说这是唯一有价值的答案是不合理地缩小了问题的范围。例如,您假设制作的唯一游戏是在营利性组织内的(显然并非如此)。您还假设对OP而言,显而易见的是,尽早进行优化会导致花费更多的时间(因此,如果我们谈论的是业务,则会花费更多的钱)。实际上,OP的问题表明他对此不确定。
JBentley '17

6

从定义上讲,优化是将解决方案的效率提高到失去功效的过程。然后,此过程意味着减少了解决方案的空间。

在软件开发的早期阶段,仍然存在“隐藏需求”:如果您减少解决方案的空间过多,您可能最终会遇到无法弹出“隐藏需求”的情况在开发的后期,迫使您修改体系结构,以这种方式增加不稳定性和可能的​​不良行为。

然后的想法是使整个解决方案正常工作,然后,当所有要求都已确定并实现时,收紧代码。然后您将看到,由于与较新需求的交互作用,您原本会在编码时轻松实现的许多优化现在不再可行。

解决方案的实际空间总是比我们开始时期望的空间大,因为我们无法完全了解非常复杂的系统。

首先使它工作。然后收紧绳索。


2
我认为“功效”不是您要追求的词,而是“产生效果的力量”,因此从某种意义上说,优化就是提高功效。您要使用某些特定版本的功效吗?(您可以链接到它吗?)您是说灵活性之类的吗?
doppelgreener

2
@doppelgreener这意味着您可以使解决方案更加有效,直到不再产生您想要的效果...
immibis

1
“首先使它起作用。然后系紧绳索。” -它的价值必须与其余答案的总和一样多。更不要说其他东西不好。
ebyrob

1
@ebyrob:还有一句话:“使它工作,使其正确,使其快速” wiki.c2.com/?MakeItWorkMakeItRightMakeItFast
ninjalj

@ninjalj也很好。当然,老板总是告诉我:“别着急,说对了。” 因此,我不知道您说的话是否与原始海报要求的详细信息一样普遍。
ebyrob'5

2

简而言之,如果您想稍后进行更改,那么尽早进行优化常常会浪费很多精力,然后您发现您已经将易于更改的代码结构优化为更低的层次,现在您需要将其重新更改为较高的层次。级方法,并再次优化结果。

对于喜欢专注于从“完成有用的工作”(例如优化)中获得乐趣的新手开发人员而言,这是一个常见的错误,他们没有考虑是否是适当的时机。当您获得对大型项目(例如游戏)进行编程的经验时,您将了解何时可以保证优化现有代码库以及何时进行优化。不要害怕犯这个错误,您只会从中学到东西而受益。

通常,只有当您确实不能立即进行开发时,才进行优化。就像您每秒创建和删除数百万个对象60次一样。

因此,就学习经验而言,尽早优化几次是很好的:p


2

优化的重点是使计算机在代码上运行最佳,而开发则需要使程序员在代码上运行最佳。

优化并不会带来见解。它使计算机工作更少,而程序员更多。

当然,有不同的类别,例如设计汽车。在构建第一个底盘之前优化引擎没什么问题,但是在不知道引擎形状之前优化底盘可能会浪费时间。模块化和规格可以在很多地方进行优化工作,甚至在整个产品组装之前。


通过定义优化之外的其他方法,并谈论游戏开发中的实际情况,而不是去模仿汽车,可以改善这一点。
doppelgreener

一个重言式问题的完美答案。
Fattie

2

我强烈反对所有不应在早期阶段对代码进行优化的声明。这取决于您处于哪个阶段。如果这是MVP-原型,而您只是想看一下需要1-2周的游戏,那么您就可以重写已经编写的所有内容。是的,优化并不重要。但是,如果您已经在开发要发布的游戏,那么它应该一直在优化代码。人们谈论新功能和可以添加的内容的故事是误解。这是设计不良的代码体系结构,而不是优化的代码。如果您的代码设计不错,则无需重写任何内容即可添加新元素。

例如,如果您有A *寻路算法,以最佳方式编写它会更好吗?而不是稍后更改您的一半代码,因为您必须对算法进行某些更改,因为现在它需要另一个方法调用和回调?如果您从一开始就已经有了优化的代码,它将为您节省大量时间。因为您可以绘制对象之间的关系以及它们之间的交互方式,而不是盲目地制作大量新脚本并立即建立所有连接,所以这会导致模糊的sphagetti代码。

我要添加的最后一件事是,即使您不想再制作游戏了,您也可以使用优化的A *算法,将其用于下一个游戏。可重用性。例如,许多游戏具有清单,寻路,程序生成,npc之间的交互,战斗系统,AI,界面交互,输入管理。现在您应该问自己-“我从头开始重写了那些元素几次?” 他们占比赛的70-80%。您真的需要一直重写它们吗?如果未对它们进行优化怎么办?


5
如果A *代码应该开始优化,那么“优化”如何优化?在进行基准测试之前,您是否在组装中手动编码?我认为,在进行基准测试之前,通常应该在微优化方面进行一些不重要的工作。在微优化方面,优化的编译器可能比您做得更好,并且便宜得多。
gmatht

@gmatht好吧,A *可能会有所不同,因为我说过它的设计可能很差并且不能很好地工作。但是它可以是多线程的,基于斐波那契堆,具有一些预测,可以分成多个块。如果我们正在谈论寻路,我们可以添加流场与A *混合。还可以平滑,多高。也许A *不是最好的例子,但是正如我说的那样,优化与实际更改代码无关,开发人员正在更改代码是因为它的设计不佳,例如他没有遵循SOLID作为1个原因。已经很好地编写了此A *,则不再需要编写它。
坦率的月亮_Max_

@gmatht微观优化实际上不是问题。我认为OP意味着更多地是计算AI行为或着色器或其他任何东西的最好,最有效的方式。
坦率的月亮_Max_

如果您知道如何有效地编写这些东西,那么我看不到这样做的问题。这将花费相同或更少的时间。它更多地取决于开发人员的经验。作为一名程序员,如果我知道更好的解决方案,我将不会编写糟糕的解决方案。如果我知道如何编写斐波那契堆,则不会使用List和sorting来获取最小值或最大值。当然,代替使用List.Sort();会花费更多的时间和精力来编写它。,但是如果我已经有一个可重用的设备怎么办?
坦率的月亮_Max_

2
@CandidMoon我不同意“这将花费相同或更少的时间。” 编写高效的代码。也许编写代码的时间并不是很短,但效率显然不是低下的,但是当您的“有效”概念意味着考虑缓存争用,添加多线程,使用仅在某些CPU上可用的CPU特定内在函数,由于O而切换大N的算法时, (N log N)vs O(N)-这种事情很难并且容易出错,并且比简单的实现花费更多的时间。仅当您知道它将对最终结果产生实质性影响时,才进行此操作。
Michael Anderson
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.