87

クヌートが言ったように、

約 97% の確率で、わずかな効率性を忘れる必要があります。時期尚早の最適化は諸悪の根源です。

これは、「最も効率的なループ メカニズムはどれか」、「SQL 最適化手法はどれか」などの質問に対する Stack Overflow の回答でよく出てくるものです。(など)。これらの最適化のヒントに関する質問に対する標準的な回答は、まずコードをプロファイリングして、問題があるかどうかを確認することです。問題がない場合は、新しい手法は必要ありません。

私の質問は、特定の手法が異なっていても、特に不明瞭または難読化されていない場合、それは本当に時期尚早の最適化と見なすことができるのでしょうか?

The Fallacy of Premature Optimizationと呼ばれる Randall Hyde による関連記事を次に示します。

4

20 に答える 20

113

Don Knuth は、コンピューター コードの最も重要な機能は、プログラマーの意図を人間の読者に伝えることであると信じていたため、識字プログラミング運動を開始しました。パフォーマンスの名の下にコードを理解しにくくするコーディング手法は、時期尚早の最適化です。

最適化の名の下に導入された特定のイディオムは非常に人気があり、誰もがそれらを理解し、時期尚早ではなく期待されるようになりました。例としては

  • Cで配列表記の代わりにポインター演算を使用する。

    for (p = q; p < lim; p++)
    
  • 次のように、Lua でグローバル変数をローカル変数に再バインドします。

    local table, io, string, math
        = table, io, string, math
    

そのようなイディオムを超えて、危険を冒して近道をしてください

すべての最適化は時期尚早です。

  • プログラムが遅すぎる(多くの人がこの部分を忘れています)。

  • 最適化によって物事が改善される可能性があることを示す測定値(プロファイルなど) があります。

(メモリを最適化することもできます。)

質問に対する直接の回答:

  • あなたの「異なる」テクニックがプログラムを理解しにくくしている場合、それは時期尚早の最適化です。

編集: コメントに応えて、挿入ソートのような単純なアルゴリズムの代わりにクイックソートを使用することは、誰もが理解し、期待するイディオムのもう 1 つの例です。(ただし、ライブラリの並べ替えルーチンを使用する代わりに独自の並べ替えルーチンを作成する場合は、十分な理由があることを願っています。)

于 2008-12-22T04:06:56.453 に答える
42

私見、最適化の 90% は、認識された現在の要件、さらに重要なことには将来の要件に基づいて、設計段階で行われる必要があります。アプリケーションが必要な負荷にスケーリングしないためにプロファイラーを使用する必要がある場合は、放置するのが遅すぎます。IMO は問題を修正できずに多くの時間と労力を浪費することになります。

通常、価値のある唯一の最適化は、速度の面で桁違いのパフォーマンスの向上、またはストレージまたは帯域幅の面で乗数を得る最適化のみです。これらのタイプの最適化は通常、アルゴリズムの選択とストレージ戦略に関連しており、既存のコードに戻すことは非常に困難です。それらは、システムを実装する言語の決定に影響を与えるほど深くなる可能性があります。

したがって、私のアドバイスは、コードではなく要件に基づいて早期に最適化し、アプリの寿命を延ばす可能性を検討することです。

于 2008-12-22T09:06:01.747 に答える
34

プロファイリングしていない場合は、時期尚早です。

于 2008-12-22T05:13:15.040 に答える
28

私の質問は、特定の手法が異なっていても、特に不明瞭または難読化されていない場合、それは本当に時期尚早の最適化と見なすことができるのでしょうか?

ええと...つまり、同じコスト (使用、読み取り、変更の労力が同じ) と 1 つがより効率的な 2 つの手法を手元に用意できます。いいえ、その場合、より効率的なものを使用することは時期尚早ではありません.

コード作成を中断して、一般的なプログラミング構造/ライブラリ ルーチンの代替案を探します。たまたまどこかにもっと効率的なバージョンがぶら下がっている可能性があります。 ..それは時期尚早です。

于 2008-12-22T04:02:10.020 に答える
11

時期尚早の最適化を回避するという概念全体で私が目にする問題は次のとおりです。

言うことと実行することの間には隔たりがあります。

私は多くのパフォーマンス チューニングを行い、適切に設計されたコードから大きな要素を絞り出しました。 これが例です。

ほとんどすべての場合、パフォーマンスが最適ではない理由は、私がギャロッピング一般性と呼んでいるものです。これは、抽象的な多層クラスと徹底的なオブジェクト指向設計の使用であり、単純な概念は洗練されていませんが、完全に十分です.

また、通知駆動型アーキテクチャや、オブジェクトのブール型プロパティを設定するだけで活動に無限の波及効果をもたらすことができる情報隠蔽など、これらの抽象的な設計概念が教えられる教材では、その理由は何ですか? 効率

では、それは時期尚早の最適化でしたか?

于 2009-11-23T22:27:53.930 に答える
9

まず、コードを機能させます。次に、コードが正しいことを確認します。第三に、それを速くします。

ステージ#3の前に行われるコード変更は、間違いなく時期尚早です。その前に行った設計の選択をどのように分類するか(適切なデータ構造を使用するなど)は完全にはわかりませんが、パフォーマンスが優れている人よりも、プログラミングが簡単な抽象化を使用することを好みます。プロファイリングの使用を開始し、結果を比較するための正しい(ただし頻繁に遅い)リファレンス実装を作成できる段階。

于 2008-12-22T09:46:34.690 に答える
8

データベースの観点から言えば、設計段階で最適設計を考慮しないのは無謀です。データベースのリファクタリングは簡単ではありません。設計が不十分になると (これは最適化を考慮しない設計とは、時期尚早の最適化のナンセンスの背後にどのように隠そうとしても、そうです)、データベースが基本的すぎるため、そこから回復することはほとんどありません。システム全体の操作。予想される状況に最適なコードを考慮して正しく設計する方が、アプリケーション全体でカーソルを使用したために 100 万人のユーザーがいて大声で叫ぶまで待つよりもはるかにコストがかかりません。sargeable コードの使用、可能な限り最良のインデックスとなるように見えるものを選択するなどのその他の最適化は、設計時にのみ行うのが理にかなっています。クイックアンドダーティと呼ばれるのには理由があります。うまく機能することは決してないため、優れたコードの代わりに素早さを使用しないでください。また、率直に言って、データベースのパフォーマンス チューニングを理解すると、パフォーマンスの低いコードを作成するよりも、パフォーマンスが向上する可能性が高いコードを同じかそれより短い時間で作成できます。優れたパフォーマンスを発揮するデータベース設計とは何かを学ぶのに時間をかけないのは、開発者の怠惰であり、ベスト プラクティスではありません。

于 2008-12-22T16:20:21.340 に答える
7

あなたが話しているように見えるのは、多くのキールックアップが行われるときに、ハッシュベースのルックアップコンテナと配列のようなインデックス付きのコンテナを使用するような最適化です。これは時期尚早の最適化ではなく、設計段階で決定する必要があります。

Knuth ルールが対象とする最適化の種類は、最も一般的なコードパスの長さを最小限に抑えることです。たとえば、アセンブリで書き直すか、コードを単純化して、一般的でないようにすることで、最も実行されるコードを最適化します。しかし、コードのどの部分がこの種の最適化を必要とするかを確認するまで、これを行っても意味がありません。最適化を行うと、コードの理解や維持が難しくなります (可能性がありますか?)。したがって、「時期尚早の最適化はすべての悪の根源です」。

クヌースはまた、最適化する代わりに、プログラムが使用するアルゴリズム、つまり問題に対するアプローチを変更する方が常に良いと述べています。たとえば、少し調整するだけで最適化により速度が 10% 向上する可能性がありますが、プログラムの動作方法を根本的に変更すると、10 倍速くなる可能性があります。

この質問に投稿された他の多くのコメントへの反応: アルゴリズムの選択 != 最適化

于 2008-12-22T13:04:07.553 に答える
6

格言の要点は、通常、最適化は複雑で入り組んでいるということです。そして通常、アーキテクト/デザイナー/プログラマー/メンテナーは、何が起こっているのかを理解するために、明確で簡潔なコードを必要とします。

特定の最適化が明確で簡潔な場合は、自由に試してみてください (ただし、戻ってその最適化が効果的かどうかを確認してください)。ポイントは、パフォーマンスの利点が最適化の作成と維持にかかるコストを上回るまで、開発プロセス全体を通してコードを明確かつ簡潔に保つことです。

于 2008-12-22T04:05:36.987 に答える
4

プログラミング時には、多くのパラメータが重要です。これらの中には次のものがあります。

  • 可読性
  • 保守性
  • 複雑
  • 堅牢性
  • 正しさ
  • パフォーマンス
  • 開発時間

最適化 (パフォーマンスを向上させる) は、多くの場合、他のパラメーターを犠牲にして行われるため、これらの領域での「損失」とのバランスを取る必要があります。

うまく機能するよく知られたアルゴリズムを選択するオプションがある場合、多くの場合、事前に「最適化」するコストは許容されます。

于 2008-12-22T09:17:13.707 に答える
4

パフォーマンスの問題が確認された場合にのみ最適化を試みます。

時期尚早の最適化の私の定義は、「パフォーマンスの問題であることがわかっていないコードに無駄な労力を費やす」ことです。最適化のための時間と場所が必ずあります。ただし、秘訣は、追加コストがアプリケーションのパフォーマンスに影響を与え、追加コストがパフォーマンス ヒットを上回る場合にのみ追加コストを費やすことです。

コード (または DB クエリ) を書くとき、私は「効率的な」コード (つまり、目的の機能を迅速かつ完全に実行し、最も単純なロジックを合理的に実行するコード) を書くよう努めています。「効率的な」コードは必ずしも「最適化された」コードと同じではないことに注意してください。コード。最適化により、コードがさらに複雑になり、そのコードの開発と保守の両方のコストが増加することがよくあります。

私のアドバイス: メリットを定量化できる場合にのみ、最適化のコストを支払うようにしてください。

于 2008-12-22T05:43:54.400 に答える
4

最適化は、非常に高レベルから非常に低レベルまで、さまざまなレベルの粒度で発生する可能性があります。

  1. 優れたアーキテクチャ、疎結合、モジュール性などから始めます。

  2. 問題に適したデータ構造とアルゴリズムを選択します。

  3. より多くのコード/データをキャッシュに収めようとして、メモリを最適化します。メモリ サブシステムは CPU よりも 10 倍から 100 倍遅く、データがディスクにページングされると 1000 倍から 10,000 倍遅くなります。個々の命令を最適化するよりも、メモリ消費に注意を払う方が大きな利益が得られる可能性が高くなります。

  4. 各関数内で、フロー制御ステートメントを適切に使用します。(不変式をループ本体の外に移動します。スイッチ/ケースなどで最も一般的な値を最初に置きます。)

  5. 各ステートメント内で、正しい結果が得られる最も効率的な式を使用してください。(乗算とシフトなど)

除算式とシフト式のどちらを使用するかについての細かい選択は、必ずしも時期尚早の最適化ではありません。最初にアーキテクチャ、データ構造、アルゴリズム、メモリ フットプリント、およびフロー制御を最適化せずにそうするのは時期尚早です。

もちろん、目標パフォーマンスのしきい値を定義しない場合、最適化は時期尚早です

ほとんどの場合、次のいずれかです。

A) 高レベルの最適化を実行することで目標パフォーマンスのしきい値に到達できるため、式をいじる必要はありません。

また

B) 考えられるすべての最適化を実行した後でも、目標のパフォーマンスしきい値を達成できず、低レベルの最適化では、読みやすさの損失を正当化するのに十分なパフォーマンスの違いが得られません。

私の経験では、ほとんどの最適化の問題は、アーキテクチャ/設計またはデータ構造/アルゴリズム レベルで解決できます。メモリ フットプリントの最適化は、多くの場合 (常にではありませんが) 求められます。ただし、フロー制御と式ロジックを最適化する必要はほとんどありません。実際に必要な場合でも、それで十分な場合はめったにありません。

于 2008-12-24T21:07:12.617 に答える
3

プロファイラーを使用する必要性は、極端な場合に備えておく必要があります。プロジェクトのエンジニアは、パフォーマンスのボトルネックがどこにあるかを認識している必要があります。

「時期尚早の最適化」は信じられないほど主観的だと思います。

コードを書いていて、ハッシュテーブルを使用する必要があることがわかっている場合は、それを行います。何らかの欠陥のある方法で実装し、1 か月後または 1 年後に誰かが問題を抱えているときにバグ レポートが届くのを待つことはしません。

再設計は、最初から明らかな方法で設計を最適化するよりもコストがかかります。

明らかに、最初はいくつかの小さなことが見落とされますが、これらが重要な設計上の決定になることはめったにありません。

したがって、設計を最適化しないことは、それ自体がコードの匂いであるという IMO です。

于 2008-12-22T13:14:46.893 に答える
3

ノーマンの答えは素晴らしいです。どういうわけか、実際にはベストプラクティスである「時期尚早の最適化」を日常的に行っています。

たとえば、ノーマンのリストに追加するには:

  • String + String (ループ内) の代わりに、Java (または C# など) で StringBuilder 連結を使用する。
  • 次のように C でループすることを回避しますfor (i = 0; i < strlen(str); i++)(ここでの strlen は、各ループで呼び出されるたびに文字列をウォークする関数呼び出しであるため);
  • ほとんどの JavaScript 実装ではそうですが、実行する方が高速でありfor (i = 0 l = str.length; i < l; i++)、それでも読み取り可能です。

等々。しかし、そのようなマイクロ最適化は、コードの可読性を犠牲にしてはなりません。

于 2008-12-22T08:08:09.023 に答える
1

私にとって時期尚早な最適化とは、実際にシステムを動作させる前、実際にシステムをプロファイリングしてボトルネックがどこにあるかを知る前に、コードの効率を改善しようとすることを意味します。その後も、多くの場合、最適化よりも可読性と保守性が優先されます。

于 2008-12-22T04:06:38.933 に答える
1

認識されているベスト プラクティスが時期尚早の最適化であるとは思いません。それは、使用シナリオに応じてパフォーマンスの問題が発生する可能性がある場合に、時間を費やすことです。良い例: オブジェクトがボトルネックであるという証拠が得られる前に、オブジェクトのリフレクションを最適化しようとして 1 週間を費やした場合、時期尚早に最適化しています。

于 2008-12-22T04:36:32.260 に答える
1

ユーザーまたはビジネスのニーズにより、アプリケーションのパフォーマンスを向上させる必要があることが判明しない限り、最適化について心配する理由はほとんどありません。それでも、コードのプロファイルを作成するまでは何もしないでください。次に、最も時間がかかる部分を攻撃します。

于 2008-12-22T05:50:56.210 に答える
0

私の見方では、さまざまなシナリオでどれだけのパフォーマンスを得ることができるかを知らずに何かを最適化するのは時期尚早の最適化です。コードの目標は、人間にとって読みやすいものにすることです。

于 2008-12-22T05:37:24.007 に答える
0

同様の質問に投稿したように、最適化のルールは次のとおりです。

1) 最適化しない

2) (専門家のみ) 後で最適化する

最適化が時期尚早なのはいつですか? いつもの。

例外はおそらく、設計、または頻繁に使用される適切にカプセル化されたコードにあります。以前、私はタイム クリティカルなコード (RSA 実装) に取り組んだことがあり、コンパイラが生成したアセンブラを見て、内側のループ内の不要な命令を 1 つ削除すると、30% の速度向上が得られました。しかし、より洗練されたアルゴリズムを使用することによるスピードアップは、それよりも桁違いでした。

最適化する際に自問すべきもう 1 つの質問は、「ここで 300 ボー モデムの最適化と同等のことを行っているか?」ということです。. 言い換えれば、ムーアの法則によって、あなたの最適化はやがて意味をなさないものになるでしょうか。スケーリングの多くの問題は、問題にハードウェアを投入するだけで解決できます。

最後になりましたが、プログラムの進行が遅くなりすぎる前に最適化するのは時期尚早です。あなたが話しているのが Web アプリケーションの場合は、負荷をかけた状態で実行してボトルネックがどこにあるかを確認できますが、他のほとんどのサイトと同じスケーリングの問題が発生し、同じ解決策が適用される可能性があります。

編集:ちなみに、リンクされた記事に関して、私は行われた仮定の多くに疑問を呈します. まず、ムーアの法則が 90 年代に機能しなくなったというのは事実ではありません。第二に、ユーザーの時間はプログラマーの時間よりも価値があるかどうかは明らかではありません。ほとんどのユーザーは (控えめに言っても) 利用可能なすべての CPU サイクルを必死に使用しているわけではなく、おそらくネットワークが何かを行うのを待っています。さらに、プログラマーの時間が別の実装に費やされ、ユーザーが電話をしている間にプログラムが行うことを数ミリ秒短縮するために、機会費用が発生します。それより長いものは通常、最適化ではなく、バグ修正です。

于 2008-12-22T11:43:22.367 に答える