私にとってのクヌースの引用の重要な側面は、「ペニーワイズでパウンドバカ」です。それが彼が最終的に時期尚早なオプティマイザーを説明した方法です.1ポンド節約する必要があるときにペニーを節約することについて議論し、「最適化された」ソフトウェアを維持するのに苦労している人.
多くの人がクヌースの論文のほんの一部しか引用していないことがよくあります。彼の論文は、ソフトウェアの重要な実行パスgoto
を高速化するために使用することを主張していたことを理解する価値があります。
より完全な引用:
[...] たとえば、n の平均値が約 20 で、検索ルーチンがプログラムで約 100 万回実行される場合、これは全体的な実行速度の顕著な節約になります。[goto を使用した] このようなループの最適化は、習得するのが難しくありません。前述したように、プログラムのほんの一部に適していますが、多くの場合、大幅な節約が得られます。[...]
今日のソフトウェア エンジニアの多くが共有している従来の通念は、小さなことの効率性を無視することを求めています。しかし、これは、「最適化された」プログラムをデバッグしたり維持したりすることができない、小銭のない愚かなプログラマーによって実行されているのを彼らが見ている乱用に対する単純な過剰反応であると私は信じています。確立されたエンジニアリング分野では、12% の改善は簡単に達成できますが、限界とは見なされません。そして私は、ソフトウェア工学においても同じ視点が普及するべきだと信じています。もちろん、単発の仕事でわざわざそのような最適化を行うつもりはありませんが、質の高いプログラムを準備するという問題の場合、そのような効率を否定するツールに自分自身を制限したくありません。
効率の目標が乱用につながることは間違いありません。プログラマーは、プログラムの重要でない部分の速度について考えたり心配したりするために膨大な時間を浪費します。これらの効率化の試みは、デバッグやメンテナンスを考慮すると、実際には大きなマイナスの影響を及ぼします。97% の確率で、小さな効率を忘れる必要があります。時期尚早の最適化は諸悪の根源です。
プログラムのどの部分が本当に重要であるかをアプリオリに判断するのはしばしば間違いです。測定ツールを使用してきたプログラマーの普遍的な経験は、彼らの直感的な推測が失敗するということだからです。このようなツールを 7 年間使用してきた私は、今後作成されるすべてのコンパイラーは、プログラムのどの部分が最もコストがかかるかを示すフィードバックをすべてのプログラマーに提供するように設計されるべきであると確信しました。実際、このフィードバックは、特にオフにされていない限り、自動的に提供されるはずです。
プログラマーが自分のルーチンのどの部分が本当に重要かを理解したら、ループを 2 倍にするなどの変換を行う価値があります。この変換によってgo to
ステートメントが導入されることに注意してください。他のいくつかのループの最適化も同様です。
つまり、これは実際にマイクロレベルでのパフォーマンスに深く関心を持っていた人から来ており、当時 (オプティマイザーは今でははるかに優れています)、速度goto
のために を利用していました。
この Knuth による「時期尚早のオプティマイザ」の確立の核心は、次のとおりです。
- 過去の経験や測定値のない、直感/迷信/人間の直感に基づく最適化 (実際に何をしているのかを知らずにやみくもに最適化する)。
- ポンドよりもペニーを節約する方法での最適化 (効果のない最適化)。
- すべての効率の絶対的な究極のピークを求めています。
- 非クリティカル パスで効率を追求する。
- コードをほとんど維持/デバッグできないときに最適化しようとしています。
これは最適化のタイミングとは関係ありませんが、クリティカル パスの理解から実際にパフォーマンスを提供するものを理解するまでの経験と理解が必要です。
テスト駆動開発やインターフェース設計への主な焦点などは、Knuth の論文では取り上げられていませんでした。これらは、より現代的な概念とアイデアです。彼は主に実装に集中していました。
とはいえ、これは Knuth のアドバイスに対する良いアップデートです。最初にテストを通じて正確さを確立し、すべてを壊すことなく最適化する余地を残したインターフェース設計を目指してください。
クヌースの現代的な解釈を適用しようとすると、そこに「船」を追加します。ソフトウェアの真のクリティカル パスを測定されたゲインで最適化したとしても、世界で最も高速なソフトウェアが出荷されなければ意味がありません。それを念頭に置いておくと、より賢明な妥協をするのに役立ちます。
私は、データベースに複数回アクセスすることに傾倒しています。これは、ここでの正しい動きだと思います。プロジェクトを完了することがより重要であり、このような最適化のためにハングアップしているように感じます. 私の質問は、時期尚早の最適化を回避するときに使用する正しい戦略ですか?
あなた自身の要件を最もよく理解しているため、上記のいくつかの点を考慮して、最善の判断を下すのはあなた次第です。
私が提案する重要な要素は、これが重い負荷を処理するパフォーマンス クリティカルなパスである場合、最適化の余地を十分に残す方法でパブリック インターフェイスを設計することです。
たとえば、Particle
インターフェイスへのクライアントの依存関係を持つパーティクル システムを設計しないでください。カプセル化された状態と単一のパーティクルの実装しかない場合、最適化する余地はありません。その場合、最適化するためにコードベースにカスケード変更を加える必要があるかもしれません。レースカーは、道路が10メートルしかない場合、そのスピードを活かすことができません。代わりに、100 万個の粒子を集約するインターフェイスに向けて設計しParticleSystem
ます。たとえば、可能な場合は粒子をまとめて処理する高レベルの操作を使用します。これにより、最適化が必要であることがわかった場合に、設計を壊すことなく最適化する余地が十分に残されます。
私の完璧主義者の側は、最初からすべてを最適かつ完璧にしたいと考えていますが、これが設計をかなり複雑にしていることがわかりました.
今、この部分は少し時期尚早に聞こえます。一般に、最初のパスはシンプルにする必要があります。シンプルさは、冗長な作業を行っている場合でも、思ったよりもかなり高速で、多くの場合、手に負えません。
いずれにせよ、これらの点が少なくとも考慮すべき事項を追加するのに役立つことを願っています.