最適化が早すぎるのはなぜそんなに悪いのですか?


168

最適化について少し調べた後、ゲームを最適化するのが早すぎることは、広く認識されている罪のように思えます(文字通りどこでも)。

私はこれを本当に理解していませんが、パフォーマンスを念頭に置いて初めて開発するのではなく、ゲームのコア構造の一部を最後に変更することは非常に難しいことではありませんか?

ゲームが終了するまで待つことで最適化が必要かどうかがわかりますが、とにかくそれを行うべきではありません。プレーヤー。

最適化が早すぎるのはなぜ悪い考えなのか、誰かに説明してもらえますか?


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
ジョシュ

3
これに答えるのは簡単ではありません。「時間を無駄にします」。「買い物中にお金を節約しようとする理由は?」と尋ねることもできます。
ファッティ

27
逆に、多くのエンジニアは、「すぐに最適化しないでください」という文は単に間違っていると簡単に言っていることに注意してください。文は、単純に「最適化する対象がわかるまで最適化しないでください」である必要があります。したがって、A、B、Cの3つのシステムがある場合、Aがボトルネックではなく、実際にはCがボトルネックであれば、Aの最適化はまったく無意味です。その例では、明らかに、Aを最適化することは時間の無駄です。ですから、非常に単純に-最適化するA、BCのいずれか知るまで最適化しないでください。それが意味するのはそれだけです、それはとても簡単です。
ファッティ

2
開発中にアプリケーションの時間クラスを最適化することは、通常一定時間であるループからいくつかの命令を削除しようとすることとは非常に異なります。「forループをこのように記述すると、1つのCPU命令が節約されます」ではなく、O(n)対O(n log n)に焦点を当てます。

1
@phyrfox実際、ロード時間を短縮することのほうが印象的です。読み込み時間は3秒です。55fpsから60fpsが顕著かどうかはわかりません。
immibis

回答:


237

前文:

コメントではいくつかの異議が提起されており、それらは主に「時期尚早な最適化」と言ったときの意味の誤解に起因していると思うので、それについて少し説明を加えたかった。

「時期尚早に最適化しない」とは、「Knuthが最後までクリーンアップすることは許可されていないため、コードの記述が悪いことを意味する」という意味ではありませ

これは、「プログラムのどの部分が実際に高速化する必要があるかがわかるまで、最適化のために時間と読みやすさを犠牲にしないでください」という意味です。典型的なプログラムはほとんどの時間をいくつかのボトルネックに費やしているため、「すべて」の最適化に投資しても、ボトルネックのコードだけに同じ投資を集中させるのと同じ速度にならない場合があります。

これは、疑わしい場合、次のことを行う必要があることを意味します。

  • 書きやすく、わかりやすく、初心者にとっても簡単に変更できるコードを好む

  • さらに最適化が必要かどうかを確認します(通常は実行中のプログラムをプロファイリングしますが、以下のコメントでは数学的な分析を行っていることに注意してください。

時期尚早な最適化ではありません

  • 適切なモジュール/責任/インターフェース/通信システムを考慮した方法で選択することで、ニーズに合わせてコードを構成するためのアーキテクチャ上の決定。

  • 余分な時間をかけたり、コードを読みにくくしたりしないシンプルな効率。厳密な型指定の使用は、効率的であり、意図をより明確にすることができます。繰り返し検索する代わりに参照をキャッシュすることも、別の例です(複雑なキャッシュ無効化ロジックを必要としない限り、単純な方法を最初にプロファイルするまで、それを書くのを保留することができます)。

  • ジョブに適切なアルゴリズムを使用します。A *は、経路探索グラフを徹底的に検索するよりも最適で複雑です。また、業界標準です。テーマを繰り返し、このような実証済みのメソッドに固執することで、単純なことをするが既知のベストプラクティスに反する場合よりも実際にコードを理解しやすくすることができます。以前のプロジェクトでゲーム機能Xを一方向に実装するボトルネックに遭遇した経験がある場合は、このプロジェクトで同じボトルネックにぶつかる必要はありません。それが本当かどうかを知る必要があります。ゲーム。

これらのタイプの最適化はすべて十分に正当化されており、一般的に「時期尚早」というラベルは付けられません(8x8チェスボードマップの最先端の経路探索を実装するウサギの穴を下っていない限り...)

そこで、ゲームでこのポリシーが特に役立つと思われる理由について説明します。


特にgamedevでは、反復速度が最も貴重なものです。最終的なゲームに最終的に付属するよりもはるかに多くのアイデアを実装して再実装し、「楽しみを見つけよう」とすることがよくあります。

メカニックを簡単かつ多分少し素朴な方法でプロトタイプ化し、翌日にプレイテストできる場合、最初に最適なバージョンを作成するのに1週間を費やした場合よりもはるかに優れた位置にいます。特にそれが吸うことが判明し、その機能を捨てることになる場合。早期にテストできるように簡単な方法で行うと、保持していないコードを最適化する無駄な作業を大幅に節約できます。

また、最適化されていないコードは、1つの正確なことを最適に実行するために微調整されたコードよりも、一般的に変更およびさまざまなバリアントの変更が簡単です。これは、壊れやすく、バグを導入したり、速度を低下させずに変更するのが難しく、困難になる傾向があります。そのため、コードをシンプルで変更しやすい状態に保つことは、ほとんどの開発全体で実行時の非効率性の価値があります(通常、ターゲット仕様以上のマシンで開発しているため、オーバーヘッドを吸収し、最初にターゲットエクスペリエンスを得ることに集中できます)。 '機能から必要なものをロックダウンし、低速であることがわかっている部分を最適化できます。

はい、開発の後半でプロジェクトの一部をリファクタリングしてスロースポットを最適化するのは難しい場合があります。しかし、先月行った最適化はそれ以降のゲームの方向性と互換性がないため、または機能とコンテンツが増えたら実際のボトルネックではないことが判明したため、開発全体でリファクタリングを繰り返していますに。

ゲームは奇妙で実験的です。ゲームプロジェクトとその技術ニーズがどのように進化し、パフォーマンスが最も厳しくなるのかを予測するのは困難です。実際には、しばしば間違ったものを心配することになります。ここでパフォーマンスの質問を検索すると、開発者が紙の資料にまったく気を取られないという共通のテーマが現れることがわかります。

劇的な例を挙げると、ゲームがGPUバウンド(珍しいことではない)である場合、CPU作業のハイパー最適化とスレッド化に費やしたすべての時間は、具体的なメリットをまったくもたらさない可能性があります。これらの開発時間はすべて、プレイヤーエクスペリエンスを向上させるために、代わりにゲームプレイ機能の実装と洗練に費やしていた可能性があります。

全体として、ゲームでの作業に費やす時間のほとんどは、ボトルネックになるコードに費やされることはありません。特に、既存のエンジンで作業している場合、レンダリングシステムと物理システムの非常に高価な内部ループは、ほとんど手に負えません。その時点で、ゲームプレイスクリプトでのあなたの仕事は、基本的にエンジンの邪魔にならないようにすることです-そこにレンチを投げない限り、おそらく最初のビルドでかなり大丈夫です。

そのため、少しのコードの衛生と予算(たとえば、簡単に再利用できる場合は繰り返し検索/構築しない、経路探索/物理クエリまたはGPUリードバックを控えめにするなど)を除いて、終わらない習慣を作ります。 -本当の問題がどこにあるかを知る前に最適化することは生産性に良いことがわかります-間違ったものを最適化する時間を無駄にせず、コードをよりシンプルで全体的に微調整しやすくします。


38
StackOverflowについては、コードの読みやすさと明快さの重要性、およびコードを時期尚早に最適化することでコードを理解しにくくする(およびバグを導入しやすくする)危険性を強調する議論があります。
DMGregory

8
すばらしい答えは、「パフォーマンスを念頭に置いて最初に開発するのではなく、ゲームのコア構造の一部を最後に変更するのは信じられないほど難しいことではないでしょうか?」もちろん、最初は効率を考慮して設計しようとします。2つの選択肢がある場合は、より効率的な選択肢を選択します。それに失敗すると、明確に定義されたインターフェイスを使用して、できるだけモジュール化されたゲームを作成します。その後、コードベース全体を再構築することなく、各モジュール内のメカニズムを変更できます。
Baldrickk

1
@Baldrickk追加の回答として共有する価値があると思います。(私は賛成します!)私の答えは、そもそも大きな問題の発生を避けるためのアーキテクチャと計画の重要性をスキップします。「プログラム開発全般」へのGizmoの言及に関しては、それがこの時期尚早な最適化の概念の由来です。上で概説したように、誤った最適化は、欠落している最適化と同じくらい簡単に技術的負債になる可能性があります。しかし、我々は、我々は現実の問題をプロファイル&見つけることができるまで、ただシンプル&読みやすさを好む、意図的に遅い方法で物事をやったことがないしていることを強調すべきである
DMGregory

1
私はおそらくあなたたちのうちで最も経験が浅いかもしれませんが、この「すべての悪の時期尚早な最適化ルート」は少し奇妙だと私は言わなければなりません。2年ほど前にUnity3Dで何かをしようとしていました。前のクエリを使用して、いくつかのLINQクエリを作成しました。私は自分のコードを見て、強い疑念を抱き始めました。計算の複雑さは恐ろしいと思いました。私は一枚の紙を取り、予想されるサイズのデータ​​でこれらのクエリを処理するには数時間かかると計算しました。そこで、あちこちで少しキャッシュを追加しました。クエリは正常に実行されていました。
gaazkam

3
したがって、デューデリジェンスを行い、最初に最も明確で直感的なコードからコードを変更する前に、問題が現実のものであることを確認しました。これは、最適化が時期尚早ではなかったことを意味します。;)「早すぎる最適化の回避」は、「不必要に高価なコードを書く」という意味ではありません。明確なパフォーマンスの問題が特定されるまで、単純さ、読みやすさ、変更の容易さを優先します。コメントはディスカッションを目的としていないため、これについてさらに話したい場合はチャットに移動できます。
DMGregory

42

注:この回答は、DMGregoryの回答に対するコメントとして始まったため、彼が述べた非常に良い点を再現していません。

「パフォーマンスを念頭に置いて初めて開発するのではなく、最後にゲームのコア構造の一部を変更することは非常に難しいことではないでしょうか?」

これは、私にとって、質問の核心です。

オリジナルのデザインを作成するときは、効率を高めるためにトップレベルで設計する必要があります。これは最適化ではなく、構造に関するものです。

例:
川を渡るシステムを作成する必要があります。明らかなデザインは橋またはフェリーです。どちらを選びますか?
もちろん、答えは交差点のサイズと交通量に依存します。これは最適化ではなく、問題に適した設計から始めることです。

設計の選択肢が提示されたら、何をしたいかに最適なものを選択します。

したがって、トラフィック量がかなり少ないと言えば、2つのターミナルを構築し、フェリーを購入してトラフィックを処理することにします。すてきなシンプルな実装
残念ながら、一度実行すると、予想よりも多くのトラフィックが発生していることがわかります。フェリーを最適化する必要があります!(それが機能し、現在橋を建設するのは良い計画ではないからです)

オプション:

  • 2番目のフェリーを購入する(並列処理)
  • 別の車のデッキをフェリーに追加(交通の圧縮)
  • フェリーのエンジンをアップグレードして高速化する(処理アルゴリズムを書き直した)

これは、元の設計を可能な限りモジュール化することを試みるべき場所です。
上記のすべてが可能な最適化であり、3つすべてを行うこともできます。
しかし、大きな構造変更をせずにこれらの変更をどのように行うのでしょうか?

明確に定義されたインターフェースを備えたモジュール設計がある場合、これらの変更を簡単に実装できるはずです。
コードが密結合されていない場合、モジュールの変更は周囲の構造に影響しません。

フェリーの追加を見てみましょう。
「悪い」プログラムは、単一のフェリーのアイデアを中心に構築され、ドック州とフェリー州を持ち、すべてをまとめて状態を共有します。これは、システムに追加のフェリーを追加できるように変更するのが難しいでしょう。
より良い設計は、ドックとフェリーを別々のエンティティとして持つことです。それらの間には密接な結びつきはありませんが、フェリーが到着し、乗客を降ろし、新しい乗客に乗り、出発できるインターフェースがあります。ドックとフェリーはこのインターフェースのみを共有します。これにより、この場合は2番目のフェリーを追加することにより、システムを簡単に変更できます。ドックは、実際にフェリーが何であるかを気にしません。心配しているのは、何か(何でも)がそのインターフェースを使用していることだけです。

tl; dr:

  • そもそも効率を考慮して設計してください。
  • 2つの選択肢がある場合は、より効率的な選択肢を選択します。
  • 明確に定義されたインターフェイスを使用して、できるだけモジュール化してコードを記述します。

その後、最適化する必要があるときにコードベース全体を再構築することなく、各モジュール内のメカニズムを変更できます。


16
初めに、フェリーをとして実装することもできます。IRiverCrossingトラフィック量がフェリーのセットアップには大きすぎることが明らかになったら、ブリッジを実装してIRiverCrossingドロップインします。もちろん、トリックはフェリーの外部APIを減らすことです。共通の機能へのブリッジで、同じインターフェースで表すことができます。
ミンダー氏

2
これらのモジュラーインターフェイス用に自動化されたテストを作成することもできます。そのため、触れているモジュール以外のものを壊すことをあまり心配することなく、すばやくリファクタリングできます。
user3067860

2
最近、OOPが非常に重要な理由の非常に良い例です。
ハイメ・ガジェゴ

1
あなたは正しい理由を打ちました。Donald Knuthのマントラは、速度が主要な要件の1つではない場合にのみ当てはまり、最適化に焦点を合わせるとメインデザインが損なわれます。ああ、ゲームは多くの場合、迅速にあるコアで、そのため早い段階での設計で考慮しなければなりません。OPの懸念(および回答)は完全に正当化されます。
ピーターA.シュナイダー

3
@AlexandreVaillancourt質問のタイトルに答える代わりに、実際に答えられる質問の重要な部分だと思うものに答えようとしました。つまり、「デザインが修正されたために最適化が後により多くの作業を行う場合なぜ早期に最適化すべきではない」(言い換え)。この回答は、DMGregoryの回答に対するコメントとして始まり、それに加えて、彼の回答を複製することはあまり意味がありません。
Baldrickk

24

「早期に最適化しない」とは、「可能な限り最悪の方法を選択する」という意味ではありません。まだプロトタイプを作成している場合を除き、パフォーマンスへの影響を考慮する必要があります。重要なのは、開発のその時点で、柔軟性、信頼性など、他のより重要なものを損なうことではありません。シンプルで安全な最適化を選びます-制限するものと自由にするものを選択します。コストを追跡します。強い型付けを使用する必要がありますか?ほとんどのゲームは正常に動作しました。gamemplayの柔軟性の興味深い用途を見つけた場合、それを削除するにはどれくらいの費用がかかりますか?

最適化されたコード、特に「スマート」コードを変更することははるかに困難です。常に良いものと悪いものを選択する選択です(たとえば、CPU時間をメモリ使用量と交換する場合があります)。その選択をするとき、あなたはすべての影響に注意する必要があります-それらは悲惨かもしれませんが、彼らはまた役立つことができます。

たとえば、司令官キーン、ウルフェンシュタイン、ドゥームはそれぞれ最適化されたレンダリングエンジンの上に構築されました。それぞれにゲームをそもそも存在させる「トリック」がありました(時間の経過とともにさらに最適化が行われていましたが、ここでは重要ではありません)。大丈夫です。ゲームの核となる部分を大幅に最適化してもかまいません。それがゲームを可能にします。特に、この特定の最適化された機能を使用すると、あまり探索されていないゲームデザインを検討できる新しい領域を探索する場合に役立ちます。最適化によってもたらされる制限により、興味深いゲームプレイも提供される場合があります(たとえば、RTSゲームのユニット数の制限は、パフォーマンスを改善する方法として開始された可能性がありますが、ゲームプレイ効果もあります)。

ただし、これらの各例では、最適化がなければゲームは存在し得ないことに注意してください。彼らは「完全に最適化された」エンジンから始めませんでした-彼らは必要性から始めて、彼らの方法を上げました。彼らは新しい技術を開発し、それらを使って楽しいゲームを作りました。また、エンジンのトリックはコードベースの可能な限り小さな部分に限定されていました-より重い最適化は、ゲームプレイがほとんど終了したとき、または興味深い新機能が出現するときにのみ導入されました。

次に、作成するゲームを検討します。そのゲームを成功させる、または破壊する技術的な奇跡は本当にありますか?無限の世界で開かれた世界のゲームを想像しているかもしれません。それは本当にゲームの中心部分ですか?それなしではゲームは機能しませんか?たぶん、現実的な地質学などで地形を制限なく変形できるゲームを考えているのかもしれません。より小さなスコープで動作させることができますか?3Dではなく2Dで動作しますか?できるだけ早く楽しいものを手に入れましょう-最適化のために既存のコードの膨大な部分を修正する必要がある場合でも、それは価値があるかもしれません。物事を大きくしてもゲームが本当に良くなるわけではないことに気付くかもしれません。

多くの最適化が行われた最近のゲームの例として、私はFactorioを指摘します。ゲームの重要な部分の1つはベルトです。何千ものベルトがあり、工場のあちこちにたくさんの個別の材料があります。ゲームは非常に最適化されたベルトエンジンで始まりましたか?番号!実際、元のベルトのデザインは最適化するのがほとんど不可能でした-ベルト上のアイテムの物理的なシミュレーションを行い、面白いことができました(これが「新しい」ゲームプレイを得る方法です-驚きのゲームプレイデザイナー)、しかし、ベルト上のすべてのアイテムをシミュレートする必要がありました。数千のベルトを使用すると、数万の物理的にシミュレートされたアイテムを取得できます。それを削除してベルトに機能​​させるだけでも、関連するCPU時間を95〜99%削減できます。メモリの局所性などを考慮しなくても。ただし、実際にこれらの制限に達した場合にのみ有効です。

ベルトを最適化するために、ベルトに関係するほとんどすべてを作り直す必要がありました。また、ベルトは最適化する必要がありました。大規模な工場には多くのベルトが必要であり、大きな工場はゲームの魅力の1つです。結局のところ、もしあなたが大きな工場を持つことができないなら、なぜ無限の世界があるのでしょうか?おもしろいことを尋ねてください-初期のバージョンはそうではありませんでした :) Javaがうまくいかないことに気付いたとき、ゲームは何度も何度も作り直され、現在の場所を取得しました。このようなゲームで、C ++に切り替えました。そして、それはFactorioにとってはうまく機能しました(まだ良いことではありましたが、始めから最適化されていませんでした-特に、これは趣味のプロジェクトであったためです。

しかし、事は、そこにあります限定された範囲の工場でできることはたくさんあります。多くのゲームがそれを示しています。制限は、自由よりも楽しみにさらに力を与えることができます。「マップ」が無限であれば、Spacechemはもっと楽しくなるでしょうか?高度に最適化された「ベルト」から始めた場合、ほとんどの場合、そのようにする必要があります。また、他のデザインの方向性を探ることができませんでした(物理学でシミュレートされたコンベヤベルトで何が面白いかを見るなど)。潜在的なデザインスペースを制限しています。まだ完成していないゲームはあまり見ないので、そのように思えないかもしれませんが、難しいのは楽しみを正しくすることです-あなたが見るすべての楽しいゲームには、おそらくそこに到達できずに捨てられた(またはさらに悪いことに、恐ろしい混乱としてリリースされました。最適化がそれを行うのに役立つ場合-先に進みます。そうでない場合... 時期尚早です。一部のゲームプレイメカニックがうまく機能すると思うが、本当に輝くために最適化が必要な場合-先に進みます。面白いメカニズムがない場合は、それらを最適化しないでください。最初に楽しみを見つけてください-ほとんどの最適化はそれを助けず、しばしば致命的です。

最後に、素晴らしい、楽しいゲームがあります。今すぐ最適化する意味がありますか?ハ!それはあなたが考えるかもしれないほど明確ではありません。楽しいものはありますか代わりにできますか?あなたの時間がまだ限られていることを忘れないでください。すべてが努力を要し、あなたはそれが最も重要な場所にその努力を集中させたいと思う。はい、「無料ゲーム」や「オープンソース」ゲームを作成している場合でも可能です。ゲームのプレイ方法をご覧ください。パフォーマンスがボトルネックになる場所に注意してください。それらの場所を最適化すると、もっと楽しくなります(これまで以上に大きく、かつてもつれた工場を建設するような)。それにより、より多くのプレイヤーを引き付けることができますか(例えば、より弱いコンピューターや異なるプラットフォームで)。あなたは常に優先順位を付ける必要があります-比率を生み出す努力を探してください。ゲームをプレイし、他の人がゲームをプレイするのを見るだけで、ぶら下がっている果物がたくさん見つかるでしょう。しかし、重要な部分に注意してください-そこに到達するには、ゲームが必要です。それに注目してください。

桜のように、最適化が終わることはないと考えてください。完了して他のタスクに進むのは、小さなチェックマークの付いたタスクではありません。常に「もう1つの最適化」を行うことができ、開発の大部分は優先順位を理解することです。最適化のために最適化を行うのではなく、特定の目標を達成するために最適化を行います(たとえば、「333 MHz Pentiumで一度に画面に200ユニット」は大きな目標です)。ターミナルゴールの前提条件ではないかもしれない中間ゴールに集中しすぎているからといって、ターミナルゴールを見失うことはありません。


factorioの開発者は、ベルトを再び最適化て、定期的にアイテムをシミュレートするだけでよく、それ以外の場合は、見ているときに位置を補間するだけだと思います。しかし、彼らはゲーム全体がベルト(およびロボット)に効果的に基づいて長い時間をかけており、人々がパフォーマンスに気づき、不平を言うまでは、それをやっていません。
イミビス

2
@immibisまさに。人々が実際に制限に達する前にパフォーマンスを向上させることは、リソースの無駄遣いであり、他の場所で使うほうがよいでしょう。最新の最適化を行っても、通常のゲームプレイ(ロケットの打ち上げ)の範囲をはるかに超えるメガファクトリーのみで問題が発生する可能性があります。しかし、これにより、はるかに重いロジスティックが必要な新しいマラソンゲームプレイ設定が可能になりました。そして再び、彼らは実際にゲームをプレイしている人々から統計を取得することでボトルネックを特定しました-ボトルネックの約半分は彼らにとって大きな驚きでした。
ルアーン

@Fattie質問は理解できますが、答えはわかりませんか?より単純な答えが可能だと言っているだけですか(例:「経済学」)?あなたのコメントがどのように建設的であると思われるかわかりません。
ルアーン

2
@Fattie答えが「ボトルネックがわかったら一度だけ最適化する」と思われる場合は、答えとして投稿してください。良い答えを得るために必要な言葉よりも多くの言葉をすでに使っているので、先に進んでください。どのような最適化が物事を良くも悪くもしないのですか?私は確かに見たことがない。私が繰り返し述べている基本的なことは、それは常にトレードオフであるということです。他の場所で費やすことができる時間、あなたの柔軟性を制限する複雑さ... 初日から最適化が必要なものもあれば、致命的なものもあります。
ルアーン

1
@Fattie「ボトルネックが何であるかを知って初めて最適化する」は、「いつ最適化すべきか」に対する答えです。「最適化が早すぎるのはなぜ悪いのか」に対する答えではありません
イミビス

10

答えの多くは「最適化」のパフォーマンスの側面に多く焦点を当てているようですが、私自身は最適化と、より抽象的なレベルで早すぎる最適化の試練を見てみたいです。

ポリオミノの助けを借りて自分の視点を詳しく説明しようとするので、私をユーモアにしてください。

作業しているフレームワークまたはエンジンによって設定されたいくつかの固定境界があるとします。

ここに画像の説明を入力してください

次に、ゲームの最初のレイヤー/モジュールの作成に進みます。

ここに画像の説明を入力してください

次に、2番目のレイヤー/モジュールを構築します。

ここに画像の説明を入力してください

この時点で、2つのモジュール間に使用可能なスペースがあることに気付く場合があり、割り当てられた境界を最大限に活用するためにそれを最適化しようとするかもしれません。

ここに画像の説明を入力してください

完璧です。現在、アプリケーションは利用可能なリソースを完全に利用していますが、アプリケーションの方が優れていますか?

アプリケーションの3番目のレイヤー/モジュールの構築に進み、突然、3番目のレイヤー/モジュールが機能していないことを認識します(おそらく、最初の計画では予測できなかったものでも)。

代替を検索し、それを見つけます。最後に、新しく選択した3番目のモジュールと互換性がないため、アプリケーションの2番目のモジュールを変更する必要があります。(ありがたいことに、最初のモジュールと多少互換性があるため、すべてを最初から書き直す必要はありません。)

それで私たちはすべてをまとめました...

ここに画像の説明を入力してください

うーん、何が起こったのかわかりますか?

最適化の時期を早めることで、最適化の対象が最終的なものではないため、実際には効率的に事態を悪化させています。

そして、後でいくつかの追加モジュールや余分な情報を追加したい場合、この時点でそれらを実行する能力がなくなる可能性があります。

ここに画像の説明を入力してください

そして、私たちのシステムの最低レベルを調整することは、他のすべてのレイヤーの下に埋められているため、もはや実行不可能です。

ただし、すぐに最適化するという衝動で待つことを選択した場合、次のような結果になります。

ここに画像の説明を入力してください

この時点で最適化を実行すると、満足のいくものが得られます。

ここに画像の説明を入力してください

少なくともあなたの何人かは、私がこれを作るのを楽しんでいたのと同じくらいこれを読んで楽しんでいたことを願っています:)そしてあなたが今あなたが主題をよりよく把握しているように感じたら-さらに良いことです。


3
広告を削除しています。どのように画像を作成したかは気にしません。唯一の重要な部分は、あなたがそれらを投稿する権利を持っているという仮定です。
Gnemlock

2
@Gnemlockはかなり公平です。私の意図は広告を目的としていませんでしたが、それがどのように簡単に誤解される可能性があるかを見ることができます。答えに何も追加しないため、そこに場所がないことに同意します。
天井のヤモリ

2
この視覚的なメタファーは非常に効果的だと思います。質問に答えるための素晴らしいアプローチ!:)
DMGregory

8

お金。

それに帰着します。お金。時は金なり*なので、より多くのお金を生み出すことが保証されていないアクティビティに費やす時間が長いほど(つまり、これらのアクティビティを投資と見なすことはできません)、無駄になるリスクが大きくなり、お金が減りますゲーム。

最適化が早すぎる場合の潜在的な副作用と、避けるべき理由を次に示します。

  • 同僚があなたを嫌っているのは、機能を取得するために一生懸命働いている間におもちゃでサンドボックスで遊ぶからです。
  • 遅延は経営陣の不満を招き、チームが納期を逃すことになり、ホリデーシーズンの前ではなく春にゲームがリリースされるため、ゲームが十分に売れなくなります。このため、本社はスタジオを閉鎖することを決定し、効果的に失業させています。そして、仕事がないということはお金がないということです。(そして、あなたは初期の最適化にあまりにも多くの時間を費やしたので誰もあなたを好きではないので、LinkedInであなたの仕事についてポジティブなレビューを書きたくはありません。

*その他の回答は、「時間」の部分を十分に強調しています


サイドノートとして、 一般的に、経験は何が早期最適化であり何が早期最適化であり、何がビジネスにとって価値があり、何がそうでないかを決定するのに役立ちます。

たとえば、ゲームAで作業し、プロジェクトの終わりまでに機能XYZがゲームループで特に重いことに気付いた場合、最終的にまったく同じ機能を持つゲームBで作業を開始し、機能を書き直し、最初から最適化することは実際には時期尚早な最適化ではありません。何もしないとボトルネックになることがわかっています。


1
有効なポイントである@JBentley。ただし、収集された経験の直接的な意味としての「なぜ」に対する結果的な答えがあります。したがって、1)早期に最適化すると、平均的な実行時間に影響を与えないコードの無駄な時間が発生する可能性があります(経験から、どのコード構成が最適化のベストプラクティスの候補であるかを知っおく必要があります)2)早期に最適化すると、コードが難しくなりますいくつかのシステムに課せられた設計上の制限のために維持するため。したがって、開発サイクルの延長/面倒なコードの維持と引き換えに得られる利益が少なすぎる可能性があります。
テオドロン

3
@JBentleyこれをDMGregoryの答えの補遺と考えてください。
アレクサンドル・ベイランクール

1
ここでこれが唯一の価値のある答えであると思われます。問題はトートロジーです。あなたにも頼むかもしれない「実際、あなたはゲームがアプリケーションストアの詳細ではなく、少ないお金を作りたいなぜ、そう?」 どうすれば答えられますか?
ファッティ

@Fattie回答にこの種の視点があると便利です。しかし、それが唯一の価値のある答えであると言うことは、質問の範囲を不当に狭めることです。たとえば、作られたゲームは営利団体内にあると仮定しています(明らかにそうではありません)。また、早期に最適化することでより多くの時間が費やされることはOPにとって明らかであると仮定しています(したがって、ビジネスについて話している場合はより多くのお金がかかります)。実際、OPの質問は、彼がこれについて確信していないことを示しています。
-JBentley

6

最適化とは、定義上、ソリューションの効率を、その有効性が失われるまで高めるプロセスです。このプロセスは、ソリューションのスペースの削減を意味します。

ソフトウェア開発の初期段階では、まだ「隠れた要件」が存在する可能性があります。ソリューションのスペースを減らしすぎると、ポップアップしたときに「隠れた要件」を満たすことができない状況になる可能性があります開発の後の段階で、この方法で不安定性と予想外の動作の可能性を追加して、アーキテクチャを変更する必要があります。

そのアイデアは、ソリューション全体を機能させることであり、その場合にのみ、すべての要件が修正および実装されたときにコードを強化します。コーディング中に一度に簡単に実装できた最適化の多くは、後の要件とのやり取りのために実行不可能になります。

ソリューションの実際の空間は、非常に複雑なシステムの完全な知識を持つことができないため、最初に予想されるものよりも常に大きくなります。

最初に機能させます。次に、ロープを締めます。


2
「効能」とはあなたが目指す言葉ではなく、「効果を生み出す力」を意味するので、ある意味で最適化とは効能を高めることです。有効性の特定のバージョンを使用しますか?(リンクできますか?)代わりに柔軟性のようなものを意味しますか?
doppelgreener

2
@doppelgreenerそれは、あなたが望む効果の生成を停止するまで、ソリューションをより効率的にすることを意味します
...-immibis

1
「最初に動作させます。次に、ロープを締めます。」-それは答えの残りの部分と同じくらいの価値がなければなりません。そして、他のものが良くなかったと言うわけではありません。
ebyrob

1
@ebyrob:別の言い回しがあります:「動作させる、正しく動作させる、高速にする」 wiki.c2.com/?MakeItWorkMakeItRightMakeItFast
ninjalj

@ninjaljそれも良いものです。もちろん、上司はいつも「急いではいけません、正しくしてください」と言っています。ですから、あなたが言っていることは、元のポスターが詳細を要求している校長と同じくらい普遍的かどうかはわかりません。
ebyrob

2

要するに、後で物事を変更したい場合、初期の最適化は非常に頻繁に無駄な労力となり、その後、簡単に変更可能なコード構造をはるかに低いレベルに最適化してしまい、それを高い値に戻す必要がありますレベルのアプローチ、および結果の最適化をもう一度行います。

これは、最適化のような「有用な作業を行った」ことから喜びを得ることに集中したい初心者開発者にとってよくある間違いであり、それが適切なタイミングであるかどうかを考えません。ゲームのような大きなプロジェクトのプログラミングの経験を積むと、既存のコードベースの最適化がいつ必要になるのか、またすぐに必要になるのかがわかります。この間違いをすることを恐れないでください、あなたはそれから学ぶことによってのみ利益を得るでしょう。

一般的に、最適化するのは、現時点で開発ビルドを実際に使用できない場合のみです。1秒間に何百万ものオブジェクトを60回作成および削除する場合のように。

したがって、学習経験の観点から、数回早期に最適化するのが良いと思います:p


2

最適化は、コンピューターをコード上で最適に動作させることに焦点を当てていますが、開発では、プログラマーをコード上で最適に動作させる必要があります。

最適化は洞察を引き出しません。これにより、コンピューターの作業が少なくなり、プログラマーの作業が増えます。

もちろん、車の設計など、さまざまなカテゴリがあります。最初のシャーシを構築する前にエンジンを最適化しても何も問題はありませんが、エンジンの形状がわからないうちにシャーシを最適化すると、時間の無駄になります。モジュール性と仕様は、製品が全体として組み立てられる前であっても、最適化作業に実行可能な多くの場所を取得できます。


これは、最適化を定義する以外の方法で先導することで改善され、車についての類推ではなく、ゲーム開発の実際の状況について話すことで改善されます。
doppelgreener

トートロジーの質問に対する完璧な答え。
ファッティ

2

コードを初期段階で最適化すべきではないというこれらすべてのステートメントには強く反対します。それはあなたがどの段階にあるかによります。これがMVP-プロトタイプであり、1〜2週間かかるゲームを見ようとしている場合は、すでに書いたすべてを書き直す準備ができていることを確認します。最適化は重要ではありません。ただし、リリースが予定されているゲームで既に作業している場合は、コードを最適化する必要があります。新しい機能や追加できるものについて人々が言う話は、誤解です。最適化されたコードではなく、設計が不十分なコードアーキテクチャです。優れたコードデザインがあれば、新しい要素を追加するために何かを書き換える必要はありません。

たとえば、A *パスファインディングアルゴリズムがある場合、できる限り最適な方法で記述した方が良いと思いませんか?後でコードの半分を変更するのではなく、別のメソッド呼び出しとコールバックが必要になったため、アルゴリズムを変更する必要があったためですか?また、最初から最適化されたコードを既にお持ちの場合、多くの時間を節約できます。膨大な数の新しいスクリプトを作成してすべての接続をすぐに作成する代わりに、オブジェクトとその相互作用の関係を自分で描くことができるため、不明瞭なスパゲッティコードにつながります。

最後に追加したいのは、ゲームをもう作成したくない場合でも、次のゲームに使用できる最適化されたA *アルゴリズムがあることです。再利用性。たとえば、多くのゲームには、インベントリ、経路探索、手順生成、NPC間の相互作用、戦闘システム、AI、インターフェイス相互作用、入力管理があります。ここで、「これらの要素をゼロから何回書き直したか」を自問する必要があります。ゲームの70〜80%です。本当にそれらを常に書き換える必要がありますか?そして、それらが最適化されていない場合はどうなりますか?


5
A *コードを最適化して開始する場合、最適化はどのように「最適化」されますか?ベンチマークを実行する前に、アセンブリで物事をハンドコーディングしますか?一般に、ベンチマークが行われるまで、マイクロ最適化に関する自明でない作業は残すべきだと思います。最適化コンパイラ、マイクロ最適化よりも優れた仕事をする可能性があり、はるかに安価です。
gmatht

@gmatht Well A *は、デザインが貧弱で、うまく機能しない可能性があると言ったため、異なる場合があります。しかし、フィボナッチヒープに基づいてマルチスレッド化でき、いくつかの予測があり、チャンクに分割できます。パス検索について話している場合は、A *と混合するフローフィールドを追加できます。また、方法の平滑化、マルチハイト。たぶんA *は最良の例ではないかもしれませんが、先ほど述べたように、最適化は実際にコードを変更することとは関係がありません。このA *を上手く書いたので、もう書く必要はありません。
率直な月_Max_

@gmathtのマイクロ最適化は実際には問題ではありません。OPは、AIの動作やシェーダーなどを計算するための最良かつ最も効率的な方法を意味すると思います。
率直な月_Max_

このことを効率的に書く方法を知っていれば、そうすることで問題が発生することはありません。それには同じ時間がかかります。開発者の経験に依存します。プログラマーとして、私がより良い解決策を知っていれば、私はくだらないものを書きません。フィボナッチヒープの記述方法を知っている場合、最小値または最大値を取得するためにリストとソートを使用しません。もちろん、List.Sort();を使用する代わりに、それを記述するのにさらに時間と労力がかかります。、しかし、私がすでに再利用可能なものを持っている場合はどうなりますか?
率直な月_Max_

2
@CandidMoon「同じ時間がかかるか、それ以下になります」には同意しません。効率的なコードを記述します。明らかに非効率ではないコードを書くのに同じ時間がかかるかもしれませんが、「効率的」という概念がキャッシュの競合を考慮し、マルチスレッドを追加し、一部のCPUでのみ利用可能なCPU固有の組み込み関数を使用し、Oにより大きなNのアルゴリズムを切り替えることを意味する場合(N log N)vs O(N)-そのようなことは難しくエラーが発生しやすく、単純な実装よりも時間がかかります。最終結果に実質的に影響を与えることがわかっている場合にのみ、それを行います。
マイケルアンダーソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.