通常、私は「時期尚早な最適化」という言葉を嫌いますが、これはそれを嫌っています。Knuth goto
が重要な領域でコードを高速化するためにステートメントを使用するようにプッシュするという文脈でこの有名な引用を使用したことは注目に値します。それが重要です:クリティカルパス。
彼は、goto
コードを高速化するために使用することを提案していましたが、クリティカルではないコードのハンチや迷信に基づいて、この種のことをしたいプログラマーに対して警告していました。
コードベース全体でswitch
可能な限り均一にステートメントを支持すること(重い負荷が処理されるかどうか)は、Knuthが「最適化された」 「1ポンド以上の節約を試みた結果、デバッグの悪夢に変わったコード。このようなコードは、そもそも効率的なことは言うまでもなく、めったにメンテナンスできません。
彼は正しいですか?
彼は非常に基本的な効率の観点から正しいです。私の知る限り、コンパイラーはswitchステートメントよりもオブジェクトと動的ディスパッチを含む多態性コードを最適化できません。そのようなコードはコンパイラーのオプティマイザーバリアとして機能する傾向があるため、LUTや多相コードからインラインコードへのテーブルにジャンプすることはありません(動的ディスパッチが実行されるまで、発生します)。
ジャンプテーブルの観点からこのコストを考えるのではなく、最適化の障壁の観点から考えるのがより便利です。ポリモーフィズムの場合、呼び出しBase.method()
は、method
仮想であり、シールされておらず、オーバーライドできる場合、実際にどの関数が呼び出されるかをコンパイラが認識できないようにします。どの関数が実際に事前に呼び出されるのかがわからないため、どの関数が呼び出されるのか実際にはわからないため、関数呼び出しを最適化して最適化の決定にさらに情報を活用することはできませんコードがコンパイルされている時間。
オプティマイザーは、関数呼び出しを覗き込んで、呼び出し元と呼び出し先を完全にフラット化するか、少なくとも呼び出し元を最適化して呼び出し先と最も効率的に作業できる最適化を行うことができます。どの関数が実際に事前に呼び出されるのかわからない場合、それはできません。
彼はただお尻を話しているだけですか?
このコストは、多くの場合1セントに相当しますが、特に拡張性が必要な場所では、これを一律に適用されるコーディング標準に変えることを正当化するのは一般的に非常に愚かなことです。それが真正の時期尚早なオプティマイザーで注意したい主なものです:彼らはマイナーなパフォーマンスの懸念を、保守性をまったく考慮せずにコードベース全体に均一に適用されるコーディング標準に変えたいと思っています。
私はそのうちの1人であるため、受け入れられた回答で使用されている「古いCハッカー」の引用には少し腹を立てます。非常に限られたハードウェアから何十年もコーディングを行ってきたすべての人が、時期尚早なオプティマイザーになったわけではありません。それでも私はそれらにも出会い、一緒に仕事をしました。しかし、これらのタイプは、分岐の予測ミスやキャッシュミスのようなものを測定することはありません。彼らはより良く知っていると考え、今日では当てはまらず、時には当てはまらない迷信に基づいた複雑な生産コードベースで非効率の概念に基づいています。パフォーマンスが重要な分野で真に働いた人は、効果的な最適化が効果的な優先順位付けであることをよく理解します。そして、保守性を低下させるコーディング標準を一般化してペニーを節約しようとすることは非常に非効率的な優先順位付けです。
非常にタイトでパフォーマンスが重要なループで10億回と呼ばれる、それほど多くの作業を行わない安価な機能がある場合、ペニーは重要です。その場合、1000万ドルの節約になります。体だけで数千ドルかかる2回呼び出される機能がある場合は、1ペニーを剃る価値はありません。車の購入中にペニーをめぐって時間を費やすのは賢明ではありません。製造業者から100万缶のソーダを購入している場合、1セント硬貨以上の値引きをする価値があります。効果的な最適化の鍵は、これらのコストを適切なコンテキストで理解することです。すべての購入でペニーを節約しようとし、他の誰もが購入しているものに関係なくペニーをハグしようとする人は、熟練したオプティマイザーではありません。