最適化が時期尚早ではなく、したがって悪ではないのはいつですか?


75

「時期尚早の最適化はすべての悪の根源」は、私たちのほとんどすべてが聞いたり読んだりしたものです。どのような最適化が時期尚早ではないか、つまりソフトウェア開発のすべての段階(高レベル設計、詳細設計、高レベル実装、詳細実装など)でどのような最適化がどの程度最適化されるのかを知りたいのですが、それはダークサイドに渡ることはありません。



回答:


116

経験を基にしていますか?悪ではありません。「Xを実行するたびに、パフォーマンスに大きな打撃を受けました。今回は、Xを完全に最適化するか、完全に回避することを計画しましょう。」

比較的痛みがないときは?悪ではありません。「これをFooまたはBarのいずれかとして実装すると、同じくらい多くの作業が必要になりますが、理論的には、Barははるかに効率的であるはずです。それを禁止しましょう。」

あなたがひどくスケーリングするくだらないアルゴリズムを避けているときは?悪ではありません。「当社の技術リーダーは、提案されたパス選択アルゴリズムが要因時間で実行されると言います。それが何を意味するのかはわかりませんが、それを検討するためにseppukuをコミットすることを提案します。

悪は、あなたが実際に存在することを知らない問題を解決するために非常に多くの時間とエネルギーを費やすことに由来します。問題が確実に存在する場合、または幻の疑似問題が安価に解決される場合、悪は消え去ります。


Steve314Matthieu M.は、考慮すべきコメントでポイントを上げています。基本的に、「痛みのない」最適化のいくつかの種類は、それらが提供する些細なパフォーマンスアップグレードはコードの難読化の価値がないか、コンパイラが既に実行している拡張機能を複製しているため、またはその両方のために単に価値がありません。あまりにも巧妙な非改善のいくつかの素晴らしい例については、コメントを参照してください。


22
時々、ファントムの問題を簡単に解決することは、読みにくく、コードの保守が難しくなる可能性があるため、やや悪です。それほど難しくはありません(または簡単な解決策ではありません)が、場合によってはまだ関連性があります。例としては、一部の人々が認識しない巧妙なビット単位のトリックを使用する場合があります。コンパイラーは、有用な場合におそらく適用されます。
Steve314

26
私はここでスティーブに同意します。特にコンパイラは非常に優れているため、「最適化」は単に価値がない場合があります。例?iが符号なしの場合、i / 2に置き換えることができますi >> 1。速いです。しかし、それはより不可解です(誰もが効果を見るとは限りません。しかし、最悪なのは、コンパイラがとにかくそれを行うということですので、なぜソースコードを難読化します;)?
マチューM.

19
@ラリー:私はしなかったので、良い例だと思います。
ジョリスメイズ

18
彼らは、コードのreadabiliy / maintainabiliyに影響を与える場合は、私の見解では、最適化も簡単なものは、また悪みなされるべきである、実際のパフォーマンスの測定に基づいていません。
バートヴァンインゲンシェナウ

14
@マシュー:彼らに何を教えますか?汚れた不要なトリック?どうして?場合は、プロファイリングがあることを示しi/2、実際のホットスポットであり、その(信じられない、しかし、のが前提としましょう)i>>1、それはより速くなりますので、このプロファイリングは、これが高速であることを示したこと、それを行うと、それにコメントを置きます。これが実際にどこでも必要な場合(マシューが言ったように、コンパイラは自分でこれを行うのに十分スマートでなければならないので、私は疑います)、初心者は何かを学びます。不要な民間伝承を持つ彼らの頭?
sbi

38

ライブラリはどのように使用されるのか分からないため、アプリケーションコードは必要なだけ優れている必要がありますが、ライブラリコードは可能な限り優れている必要があります。そのため、ライブラリコードを記述するときは、パフォーマンス、堅牢性、またはその他のカテゴリにかかわらず、あらゆる面で優れている必要があります。

また、アプリケーション設計するときやアルゴリズム選択するときはパフォーマンスについて考える必要があります。性能を発揮するように設計されていない場合、ハッカーの程度によってその後性能を発揮することはできず、優れたアルゴリズムを上回る最適化は行われません。


5
ライブラリコードは、「できるだけ良い」ことを目指しているかどうか、またはその目的を文書化する必要があります。コードは、消費者が適切な場合にのみ使用するという条件で、有用であるために絶対的に最適である必要はありません。
supercat

1
申し訳ありませんが、「あらゆる面で優れている」というのは、過剰なエンジニアリングのように疑わしく聞こえます。さらに、おそらく現実的ではありません-人生は常にトレードオフです。
sleske

1
設計段階を強調するために+1。意図的にその利点を検討している場合、時期尚早ではありません。
ネイサンタギー

逆に、ライブラリの使用方法がわからない場合は、ライブラリの改善に時間を費やすことでビジネス上の価値があるかどうかもわかりません。だから、それはほとんど議論ではありません。
-RemcoGerlich


17

最適化が時期尚早ではなく、したがって悪ではないのはいつですか?

善悪を言うのは難しいです。誰がその権利を持っていますか?自然を見ると、遺伝子を子孫に伝えることを含む「生存」の広い定義で、生存のためにプログラムされているようです。

だから、少なくとも私たちの基本的な機能とプログラミングによれば、最適化は繁殖の目標に沿ったものである場合には悪ではないと言うでしょう。男性には、ブロンド、ブルネット、赤毛、多くの素敵な人がいます。女の子には男がいて、彼らの中には大丈夫そうな人もいます。

おそらく、その目的に向けて最適化する必要があり、そこでプロファイラーを使用すると役立ちます。プロファイラーを使用すると、ホットスポットとその発生理由に関する詳細情報を提供することに加えて、最適化と時間をより効果的に優先させることができます。これにより、複製とその追跡に費やす自由時間が増えます。


3
誰かがこの古い栗に新鮮なテイクをもたらすのを見るのは爽快です。必要なのは、1つの文だけではなく、クヌースの引用全体を読むことだけです。
ロバートハーベイ

1
@RobertHarvey私はそこにちょっとした苦労があります-非常に多くの人がその1つの文だけを引用しているようであり、非常に多くの重要な文脈情報が最終的に失われます。私はちょっとした保証を得たので、それがそのような素晴らしい答えであるかどうかはわかりません。:-D

14

完全な引用は、最適化は時期尚早ではないときに定義されています。

優れたプログラマーは、そのような推論によって自己満足に落ち着くことはありません。重要なコードを注意深く見るのが賢明でしょう。しかし、そのコードが特定された後にのみ。[強調鉱山]

重要なコードはさまざまな方法で特定できます。重要なデータ構造またはアルゴリズム(たとえば、頻繁に使用されるか、プロジェクトの「コア」)が主要な最適化を提供し、多くの小さな最適化がプロファイラーを通じて特定されます。


6
ええ...ランダム関数呼び出しにかかる時間を90%削減するのは良いことですが、アプリが実際に時間の80%を費やしているコードを見て、数パーセントあります。

11

経験に基づいて、すべてのケースで常に「十分な」ソリューションを選択する必要があります。

最適化とは、実際に必要であることを知る前に「十分に高速化するよりも複雑なコード」を書くことを意味し、コードを必要以上に複雑にします。複雑さは物事を難しくするものなので、それは良いことではありません。

つまり、単純な並べ替えを行う場合は、「ディスクに透過的にスワップすることで100 Gbファイルを並べ替えることができる」という非常に複雑な並べ替えルーチンを選択しないでください。バブルソートを盲目的に選択するか、「すべてのエントリをランダムに選択して、順序が正しいかどうかを確認します。繰り返します。」めったに良いことではありません。


3

私の一般的な経験則:最適化が必要かどうかわからない場合は、最適化しないと仮定します。ただし、最適化が必要な場合には注意してください。ただし、事前に知っておくべき問題がいくつかあります。これには通常、適切なアルゴリズムとデータ構造の選択が含まれます。たとえば、コレクションのメンバーシップを確認する必要がある場合は、何らかのタイプのセットデータ構造が必要になることを確信できます。


3

私の経験では、詳細な実装フェーズでの答えはコードのプロファイリングにあります。何がより高速である必要があり、何が許容できるほど高速であるかを知ることが重要です。

パフォーマンスのボトルネックがどこにあるのかを正確に知ることも重要です-実行に合計時間のわずか5%しかかからないコードの一部を最適化しても、何の効果もありません。

ステップ2と3では、時期尚早でない最適化について説明します。

  1. 動作させる
  2. テスト。十分に速くないですか?それをプロファイルします。
  3. 手順2のデータを使用して、コードの最も遅いセクションを最適化します。

ステップ0を忘れました。つまり、アプリケーションを適切に設計して、最初から妥当なパフォーマンスを期待できるようにします。
ロバートハーヴェイ

私は詳細な実装フェーズについてのみ話していました。
ゴルジコセフ

1
私はステップ#3に疑問を呈します。多くの場合、最良の答えは別のアプローチを見つけ出すことです。そうすれば、そもそもコードの遅いビットをやっていないことになります。
ローレンペクテル

1
適切なデータ構造を選択してください。
ジャソンク

3

ハードウェアプラットフォームなど、変更が難しいものを選択する場合、最適化ではありません。

データ構造の選択は良い例です-機能的および非機能的(パフォーマンス)要件の両方を満たすために重要です。簡単に変更することはできませんが、それでもアプリの他のすべてを駆動します。データ構造により、使用可能なアルゴリズムなどが変わります。


3

この質問に答える方法は1つしかありません。それは、パフォーマンスチューニングの経験を積むことです。つまり、プログラムを作成し、それらが作成された、それらのスピードアップを見つけて、繰り返し実行します。次に例を示します。

ほとんどの人が犯す間違いは次のとおりです。彼らは実際に実行するにプログラムを最適化しようとします。彼らがプログラミングのコースを実際に実践した経験のない教授から学んだ場合、彼らは大きなO色のメガネを持ち、それがすべてだと思うでしょう。事前の最適化、すべて同じ問題です。**

誰かが言った:最初にそれを正しくし、それから速くしなさい。彼らは正しかった。

しかし今、キッカーのために:これを数回行った場合、以前にスピードの問題を引き起こす愚かなことを認識し、本能的にそれらを回避します。(クラス構造を重くしすぎる、通知であふれる、関数呼び出しのサイズを時間コストと混同するなどのことは、リストが延々と続く...)経験豊富:早すぎる最適化!

だから、これらの愚かな議論は延々と続く:)

**彼らが言うもう1つのことは、コンパイラーは非常に優れており、マシンは最近非常に高速であるため、これ以上心配する必要はないということです。(KIWI-Kill It Iron)。指数関数的なソフトウェアのスローダウン(このように考えるプログラマーによって行われる)を補償できる指数関数的なハードウェアまたはシステムの高速化(非常に優秀な勤勉なエンジニアによって行われる)はありません。


2

要件または市場が具体的に要求する場合。

たとえば、低レイテンシが重要であるため、パフォーマンスはほとんどの金融アプリケーションの要件です。取引されている機器の性質に応じて、最適化は、高レベル言語での非ロックアルゴリズムの使用から低レベル言語の使用、さらには極端なものまで-ハードウェア自体での順序一致アルゴリズムの実装(たとえばFPGAを使用) )。

他の例は、いくつかのタイプの組み込みデバイスです。たとえば、ABSブレーキを取り上げます。まず、安全性があります。休憩をとると、車の速度が落ちます。しかし、パフォーマンスもありますので、休憩をとるときに遅延を望みません。


0

パフォーマンスのためにシステムの "ソフト障害"(機能しますが、それでも役に立たない)にならないものを最適化する場合、ほとんどの人は最適化を時期尚早と呼びます。

実世界の例。

  • バブルソートの実行に20ミリ秒かかる場合、クイックソートを1ミリ秒に最適化しても、2000%のパフォーマンスの向上にもかかわらず、ユーティリティ全体が意味のある方法で強化されることはありません。

  • Webページの読み込みに20秒かかり、1秒に減らすと、Webサイトの実用性が0から無限に近くなります。基本的に、遅すぎたために壊れていたものが、今では便利です。


プログラムの中でソートが1000回呼び出された場合、20ミリ秒から1ミリ秒に最適化するのは大変なことに注意することが重要です。
ビーフスター

0

どのような最適化が時期尚早ではありませんか?

アプリケーションの既知のパフォーマンスの問題を修正する最適化、またはアプリケーションが明確に定義された受け入れ基準を満たすことを可能にする最適化。

特定されたら、修正を確立するためにある程度の時間をかけ、パフォーマンスの利点を測定する必要があります。

(つまり、そうではありません-「このコードの一部は遅いように見えると思います。代わりにYを使用するようにXを変更すると、より高速になります」)。

最終的にコードを遅くする多くの時期尚早な「最適化」に遭遇しました-この例では、「考え抜かれていない」ことを意味する時期尚早を取っています。最適化の前後にパフォーマンスをベンチマークし、実際にパフォーマンスを改善するコードのみを保持する必要があります。


0

「時期尚早の最適化はすべての悪の根源」は私たちのほとんどすべてが聞いたり読んだりしたものです

本当です。残念ながら、それはまた、常に(悪意を持って)誤用されているプログラミング引用の1つでもあります。ドナルド・クヌースがミームを作ったので、引用からいくつかのオリジナルのコンテキストを追加する価値があります。

私たちは小さな効率を忘れてはいけません。時間の約97%を言ってください:早すぎる最適化はすべての悪の根源です。しかし、その重要な3%の機会を逃してはなりません。...優れたプログラマー...重要なコードを注意深く見るのが賢明でしょう。しかし、そのコードが特定された後にのみ。...測定ツールを使用してきたプログラマーの普遍的な経験は、直感的な推測が失敗することでした

Knuth が実行時の実行速度について具体的に説明したことに注意してください。

..プログラマーは、プログラムの重要でない部分の速度を考えるか、心配するのに膨大な時間を浪費します。

また、彼は1974年に、実行速度とプログラムの保守性(高速-保守性の低さ)の間にプレミアムと負の相関があるマシンリソースがおそらく現在よりも強力だったときに記事を書きました。

ドナルド・クヌースによると、問題に答えるために、特定れた(プロファイリング中に測定され、特定された)深刻なパフォーマンスのボトルネックを修正する場合、最適化は時期尚早ではありません。

前に言ったように、「時期尚早の最適化」は最も悪意のある悪用されたミームの1つです。

  • O(1)代替が存在する大きなNのデータベースへの往復回数O(N ^ 2)など、肉眼で見えるボトルネックを導入前に回避できる

さらに、実行時の実行速度にも関係しません:

  • 思慮深い先行設計

  • 静的型付け(!)

  • など/あらゆる形態の精神的努力

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.