web-dev-qa-db-ja.com

最適化に頼ることは賢明ですか?

コードを書いて自分のやっていることを明確にし、オプティマイザに頼ってコードの効率を改善する必要がありますか。

そして、他のオプションよりも1つのオプションを選択することで、どれだけの速度/サイズを失うのですか?

7
DarthRubik

2つの非常に異なる種類の最適化があります。

1つはマイクロ最適化です。たとえば、x = (y * 4 + z) / 2x = y + y + z / 2に変更したり、x = y % 8x = y & 7に変更したりします。コンパイラーはマイクロ最適化が非常に得意なので、気にしないでください。

2つ目は、アルゴリズムによる最適化です。 「構造の配列」を「配列の構造」に置き換えてコードをSIMDにより適したものにする、1つではなく複数のスレッドを使用して複数のCPUを利用する、リストを作成および変更する間リストをソートしたままにするなど「予測不可能な(CPUの場合)ポインタ追跡」を回避するために、後でソートするか、リンクリストの代わりに配列を使用する必要があります。これらはコンパイラが苦労することです。また、既存のコードにそれらをレトロフィットしようとすると、多大な労力が発生する可能性があります。そして、コードのいずれかが実装される前の設計段階でこれらのことを考慮することははるかに良いです。

4
Brendan

両方とも :-)

真剣に、 時期尚早の最適化 は問題になる可能性があります-週に1回だけ実行されるルーチンを最適化するために何百時間も費やすことになるでしょう。また、完全に最適化されたコードは、多くの場合、読み取りやデバッグが困難です。

検討してください。数日かけて1分あたり10,000件のレコードを処理できます。読みやすく、保守も簡単で、テストも簡単です。

または、1週間で1分あたり最大50,000件のレコードをプッシュできます。ただし、バグを見つけて修正するまでにさらに1週間かかる場合、実際には何も得られていません。「高速コード」によって節約された時間はすべて「追加のデバッグ」に大きく費やされています。

それを言っても(私は明確なコードを書くことを支持していることがわかります)、あなたはまだあなたが求めていることの感覚を持っているはずです行うコンパイラ。深くネストされたループは実行が遅くなり、内側のループ内の余分な操作は、予想よりもはるかに頻繁に実行されます。

パフォーマンスの問題が発生するまで明確なコードを記述します、次に測定とテスト最適化する必要があるビットがわかるまで正確にコード。

最適化の変更を行った後は、測定とテストを必ず行って、それらが機能したことを確認してください。常に機能するとは限りません。

17
Dan Pichelman

私はあなたが最適化について間違った理解を持っていると思うので、ここにそれに関するいくつかの事実があります:

まず、最適化はコードの99%とはまったく関係ありません!最適化に関する最も重要な事実です。コードの大部分が実行されることはほとんどないため、最適化による実質的な利益はありません。それ。

したがって、コードを最適化するために必要な最も重要なスキルは、最適化するwhereを決定することです。ほとんどの人はそのためにプロファイラーを使用します。

ただし、最も重要な最適化は通常、アルゴリズムレベルで行われますです。つまり、基本的なコード構造が悪い場合は、必要に応じてそれをマイクロ最適化できますが、パフォーマンスは決して低下しませんが、より有利な構造を使用した完全なくだらない実装は、いつでもそれよりも優れています。そして、より良いコード構造を見つけ、それらをあなたの利益のために使用するかどうかは、完全にプログラマー次第です。コンパイラは全体像を見ることができないため、これを行うことはできません。

私の経験では、アルゴリズムレベルで確認する必要のあるものは主に次のとおりです。

  • コピーはどこで発生しますか?

    これは、移動構築が行われるまで、C++コードの一般的な障害でした。それでも、常にデータをコピー/移動する必要はない方がよいでしょう。特に、ループ内で文字列を連結する場合に通常発生するように、2次コピーのコストが発生するのを避ける必要があります。

  • ディスクアクセス/ネットワーク通信などの高価な操作はどこで使用しますか?

    システムが回転しているディスクから単一のデータブロックをフェッチしている間、多くの計算を実行できます。したがって、高コストのオペレーションがある場合、これらは最適化する必要があるものです。あなたのコンパイラはそれで少しあなたを助けません。検索するその他の操作:ロック、システムコール、メモリ割り当て。

  • データについて尋ねる必要があるすべての質問に、簡単で低コストの方法で回答できるような方法でデータを表すことはできますか?

    これは、最もトリッキーで効果的で楽しいことです。真剣にそれを行うと、多くの問題の複雑さを線形または一定の時間の複雑さまで得ることができることがわかります。


だから、あなたの質問にもっと直接答えるには:

コードを書いて自分のやっていることを明確にし、オプティマイザに頼ってコードの効率を改善する必要がありますか。

パフォーマンスに関係のないコードの99%は、マイクロ最適化を確実に行わないはずです。それは完全に逆効果です。

そして、他のオプションよりも1つのオプションを選択することで、どれだけの速度/サイズを失うのでしょうか?

コードの99%にはありません。重要なのは最後のパーセントです。私の経験では、マイクロ最適化により2倍以上のスピードアップが簡単に得られます。しかし、私が言ったように、マイクロ最適化の力は限られています。アルゴリズムの複雑さをO(N^2)からO(1)に改善できる場合、2倍の改善とは何でしょうか。 (それでも、問題のサイズが小さすぎるため、O(N^2)アルゴリズムを使用する必要がある場合があります!)


TL、DR:徹底的な分析を行う前に、マイクロ最適化についてさえ考えないでください!

なんで、これが大事なの?何かが十分に速くないと不平を言う人はいますか?物事を行う時間は限られています。速度が本当に心配でない限り、優先順位は正確さと機能でなければなりません。

しかし、「コードの効率を改善するためにオプティマイザに依存すべきか」というのは、私には非常に悪いことのように思えます。オプティマイザはmicro optimisationsを実行します。これにより、自分でマイクロ最適化を行うという恐ろしいタスクからユーザーを救います。それは魔法を行いません。あなたはあなたのツールとあなたのライブラリが何をするか、それらがどれほど効率的であるかを知っているべきです。仕事に最も効率的なツールを使用し、不要な作業は行わないでください。ほとんどの場合、これにはknowledgeのみが必要で、実際の作業は必要ありません。

あなたの質問は私たちに2つの不健康な選択肢の選択肢を与えます。正しいことは、あなたのビジネスを学び、あなたが何をしているかを知り、そして自然に効率的な方法で物事を行うことです。ほとんどの場合、十分に効率的であり、そうでない場合は、開始するための適切な基盤があり、他の場所で無駄にしていないため、それを改善する時間があります。ゴミコードを書き、クリーンアップをオプティマイザに頼ることは悪いことです。 「最後のオンスのパワーを出すことにこだわる」ことも同様に悪いことです。

2
gnasher729

他の答えは良いです。追加できるのは

  • コンパイラーが実行できるスピードアップがあるので、命令を並べ替えたり、レジスターをジャグリングしてメモリーフェッチを節約したりするなど、それらを気にする必要はありません。

  • あなただけができるスピードアップがあります。コンパイラはそれらを行うことができません。たとえば、あなたが疑ったことのない目に見えないI/Oや、メモリ管理が多すぎます。

だから私がすることは2つのフェーズです:

  • まず、デバッグビルドで、私だけが実行できるスピードアップを取得します ここのように 。これは本質的にデバッグプロセスであり、最適化されたビルドをデバッグすることが非常に難しいため、デバッグビルドでこれを行います。

  • 次に、できる限り高速化した後、コンパイラーのオプティマイザーをオンにして、魔法のようにします。

これはかなり簡単に聞こえますが、信じられないかもしれませんが、多くの人は、コンパイラー最適化プログラムのみをプロファイルする必要があると考えています。それはあなたの目標を混乱させるのでばかげています-スピードアップを見つけることとそれがどれほど速くないかを測定することの比較。

0
Mike Dunlavey