web-dev-qa-db-ja.com

プロファイリングの前に最適化することは常に間違っていますか?

「最適化前のプロファイリング」のマントラが、SOや他の場所で何度も何度も繰り返されているのがわかります。私は確かにプロファイリングツールを使用していますが、その結果に驚くことはまれです。プロファイラーは、プログラムの実行パスの可能性を理解し、アーキテクチャーがどのように機能するかを理解し、コンパイラーがどのような最適化手法を使用できるかを理解することで合理的に推測できる同じ情報を提供しているようですあなたのために雇います。

このため、開発していると、コードの中でボトルネックになることがよくあります(多くの場合、自分でコードを書くとき、「これは、コードの重要な部分であり、高速である必要がありますが、まずは低速の実装を使用してコンセプトを証明し、後で最適化します」)。多くのプロファイリングを行う前に、これらの領域を最適化するだけです。

これは本当に悪い習慣ですか、それとも最適化の経験を積むことの自然な結果ですか?

22
Cercerilla

ここでの黄金律は「すべてが適度に」だと思います。

コードの一部がボトルネックになることがかなり確実である場合、初期の最適化を行うことは恐ろしい習慣ではありません。少なくとも、後で簡単にリファクタリングできるように対策を講じることをお勧めします。

あなたが避けたいのは、実際のデータを見てそのような努力を正当化する前に、ミクロ最適化の名のもとに時間と可読性を犠牲にすることによって、行き過ぎることです。

33
dbyrne

「最適化」と「賢明な設計」の間の境界線は、かなり細かい場合もあれば、かなり明白な場合もあります。たとえば、数百万のアイテムを並べ替える場合、O(NではなくO(N log N)アルゴリズムを使用する価値があることをプロファイラーが確認する必要はありません。2)アルゴリズム。 IMO、それは最適化ではありませんが、合理的で賢明なことに分類されます。

また、メリットがあるかもしれないという理由だけでなく、コストが最小限から存在しないという理由で、あなたがやるべきこともいくつかあります。 @unholysamplerの例を使用するには、++i の代わりに i++ポストインクリメントとして入力することに慣れている場合は、わずかなコストがかかる可能性がありますが、(多くても)一時的で簡単です。プロファイラーがreallyがその時間を必要とすることを示し、そこに保存する妥当な機会があったのでない限り、ナノ秒を節約するために作業コードを書き換えるのに時間を費やしません。同時に、新しいコードを入力するだけの場合は、慣れると無料になるので、より良いと思われるフォームを常用して作業します。それはしばしば何も得ず、違いが生じたとしても、気づいたり気にかけたりするには十分な大きさではないことがよくありますが、それでもまだ無料なので、理由はありませんnot

そのようなケースはかなり明白であり、私の心の中で、私は本当に最適化と考えるものではなく、実際には賢明な設計に該当します。 「表現なしの最適化」の他のほとんどのケースは、正当化するのがかなり難しいでしょう。最適化にかなりの時間や労力を費やす場合は、それを正当化するための「直感」よりもはるかに堅実なものが必要です。

私が言う理由の一部を追加する必要があります。それは、目標が最適化ではない場合でも、プロファイリングコードは非常に役立つと思うからです。プロファイラーは、最適化について特に気にしなくても非常に役立つコードの概要を提供します。たとえば、そのタイプのリソースを解放するためにリソースを割り当てるために10倍の呼び出しがある場合、現在コードが正常に実行されているように見えても、実際の問題があることはかなり良い手がかりです。それに到達すると、多くのコードには一致する必要がある多くのものがあり(1:1とは限らないが、どういうわけかそうです)、プロファイラーは、他のほとんどのツールよりもはるかに迅速にそのような不一致を表示できます。

12
Jerry Coffin

最適化前のプロファイリングのポイントは、ベースラインが決定する必要があるということですどのくらいの改善最適化によって得られました。プロファイラーから取得する「驚くべき」情報は次のとおりです。

  • その方法がよく呼ばれることは知っていましたが、そんなに呼ばれることに気づきませんでした。
  • スレッドモニターの競合が原因で、予期したとおりに処理が遅くなることはほとんどありません。
  • 私はそれだけ XYZのインスタンスを生成していますか?約n...

そうは言っても、プロファイラーは私の疑念を確認するだけの場合が多い。優れた科学的方法には、監視と実験の健全な投与が含まれます。それは少し難しいですが、私はプロファイラーのより体系的な問題を理解しようとします。明らかな変更を行って5%の改善を得ることができます。または、別の方法で問題に取り組み、25%の改善を得ることができるかもしれません。 (ほとんどの最適化ではそれほど大きな改善は得られませんが、場合によってはそうなります。)もちろん、ベースライン測定なしでは、最適化によってパフォーマンスがどれほど改善されたかはわかりません。

12
Berin Loritsch

「私はボトルネックになると感じることができる」(原文のまま)

このステートメントの問題は、オブザーバーエラーです。悪いと思うからといって、それがIS悪いというわけではありません。プロファイラーは経験的な証拠を提供し、改善の余地のない領域で時間を費やすのを防ぎます。そのため、最適化する前にプロファイラーから始めて、プログラムとプロファイラーが最初に遅いセクションであることを証明してみましょう。

8
jmq

既知のパフォーマンスキラーとそれらを回避する既知のベストプラクティスがあります。 SQL Serverでは、カーソルがセットベースの操作よりも遅いことを確認するためにプロファイルを作成する必要はないと思います。これを知って始めたら、コードを書くたびに2つのオプションをプロファイルする必要なしに、最初からより良いパフォーマンスのコードを書くでしょう。

既存のコードを調整している場合は、プロファイルを作成することをお勧めします。これにより、一般に非効率であることがわかっているコードが正しく機能していないことを確認できるだけでなく、自分が知らなかった問題を表示することもできます。私は、ストアドプロシージャが最適化される可能性があると疑った1つのことをプロファイリングしたことを覚えており(それは可能です)、アプリケーションが一度呼び出すだけでよいのに、アプリケーションによって数百回呼び出されることがわかりました。

さらに、プロファイリング時に実際にパフォーマンスが向上したことを証明できるという利点があります。私は個人的にこれらを数値の前後に保存し、業績評価の評価記事や、就職活動の際の成績について話し合うときに使用します。チューニングがどれだけ上手かを示す実際の数値があると便利です。

5
HLGEM

人々が言う理由は、プロファイリングが完了する前に最適化する必要がある必要がわからないためです。そのため、メリットがないために多くの時間を浪費してしまう可能性があります。

それでも、何かが悪いアイデアとしてあなたに飛びついた場合(たとえば、同僚が単純な反復ループの代わりに深い再帰を使用することを選択した場合)、それを修正できます。ただし、古いコードを海軍で見つめるのではなく、前進することに集中する必要があります。プロセスにはそれが適切な段階があります。

2
Satanicpuppy

誰もが最初から良いコードを書こうとしていると思います。それはあなたがやっていることのように聞こえます。

最初にすべきことは、デザイン、特にデータ構造を単純に保つことです。多くの場合、人々はパフォーマンスについて心配しているため、より洗練されたデータ構造、冗長データ、詳細な通知手法が必要であると想定し始めます。私の経験では、これらのことは、回避すべき問題を引き起こします。

優れたコーディングの実践と優れた設計にもかかわらず、パフォーマンスの問題が潜んでおり、それらを定期的に削除する必要があります。これらはあなたが推測できたものとほぼ決してものではなく、ほとんどのプロファイラーはそれらを見つけるのがあまり上手ではありません。さらに、コンパイラーの最適化レベルがそれらに影響を与えることはめったにありません。ほとんどの場合、それらは厳密な計算にバインドされたループではないためです。ほとんどの場合、それらは無害に見える(または見えない)関数呼び出しとして提示され、スタックをランダムにスナップショットすると、その真ん中にあり、次のように想像以上にずっと長い時間を費やしています。彼らはしばしばそこに現れます。

これが私のお気に入りの例です。

1
Mike Dunlavey

プロファイリングの前に(比較的)安全に実行できる2種類の最適化があります。

  1. アルゴリズムの最適化:平均(または最悪の場合)の複雑性がより高いアルゴリズムを選択します。これは、コーディングを開始する前に行うこともできます(すべきですか?)。選択したアルゴリズムが実際のデータセットで与えられた正しいアルゴリズムであることを確認する必要がありますが、より適切なアルゴリズムで開始することをお勧めしますね。

  2. データ構造の最適化:データを正しくレイアウトするか、局所性の高いデータ構造を使用するとパフォーマンスが向上しますが、使用できるアルゴリズムに影響を与えるため、コーディングの前にそのような最適化を行うのが簡単です(そしてしたがって、コードがない場合はプロファイラーを使用できません)。たとえば、ビデオゲームをプログラミングする場合、データの局所性、キャッシュの一貫性などのメリットがあるため、データを格納するには、構造体の配列(AoS)ではなく配列の構造体(SoA)を使用する方が一般的には適切です。

1

はい、プロファイリングの前に最適化するのは間違っています[〜#〜] but [〜#〜]

優れたプログラミング、コードをより単純でより簡単にするプログラミングは、プロファイリングを必要としません。不要な初期化をループの外に移動するような優れたプログラミングは、コードの品質を改善しているという事実以上の正当化を必要としません。

プロファイルする必要があるのは、パフォーマンスの改善を具体的に検討しているときだけです。改善を表示するには、最初にベースラインを設定してから、デルタを表示する必要があります。

最適化を装って複雑さを追加するときはいつでも、それがボトルネックであり、コードがパフォーマンスを向上させるという証拠を示さない。ただ悪いプログラミングをしているだけです。

0
dietbuddha

重要な違いは次のとおりです。

  1. 最適化されたコードは、最適化されていないコードと同じくらい簡単です。

  2. 最適化されたコードは、最適化されていないコードよりも複雑です(したがって、エラーが発生しやすく、将来修正することが困難です)。

最初のケースでは、必ず先に進んでください。 2番目のケースでは、開発時間への投資(バグの修正や機能の提供に同じ時間を使用しないことによる機会費用を含む)と、より複雑なソリューションの将来の高いメンテナンスコストを比較検討する必要があります。このコストと、パフォーマンスの改善が見られるかどうかを比較検討する必要があります。パフォーマンスコストが何であるかわからない場合、どのようにこの判断を行いますか?関数は明らかに非効率的かもしれませんが、とにかく数ミリ秒しかかからない場合、1000倍のパフォーマンス最適化では値が提供されません。それが実際に重要である最適化に取り組んでいないことの機会費用は言うまでもありません。

第2に、パフォーマンスに関する直感は非常に間違っている可能性があり、測定する前に「最適化」するかどうかはわかりません。たとえば、多くの開発者は、O(log n)アルゴリズムはO(n)よりも速いと考えがちです。しかし、あなたはそれを知りません。 O(n)アルゴリズムは、nがあるしきい値を下回っている限り、より高速になる可能性があります。そのしきい値とは何でしょうか?おそらくわからないでしょう。そして、特定のプログラムで実際にnは何ですか?通常、このしきい値の上または下ですか?どのようにして見つけますか?

直感が間違っていて、最適化によって実際にプログラムの実行が遅くなった場合はどうなりますか?前と後にプロファイリングした場合は、間違いに気付き、変更をロールバックします。最悪の場合、時間を無駄にしました。プロファイリングしない場合、あなたは賢くなく、プログラムに長期的なダメージを引き起こしています。

本当に難しい決断は、建築のさまざまな道を進むことができるときです。ネットワーク通信は、JSON over HTTP(simple)またはprotocol buffers over TCP(performant)?である必要がありますか?ここでの問題は、パフォーマンスを測定する前に、事前に決定する必要があることです。後でプロトコルを変更する必要があるため、作業を無駄にしたくありません。この場合、単純なバージョンから始めて、問題があることが判明したときに後で最適化することはできません。しかし、最もパフォーマンスの高いバージョンを選択するだけではいけません。デフォルトのいずれかです。知識に基づいた推測と予測を行う必要があります。


「頻繁ではない」プロファイリングは、プログラムの理解に基づいた直感と同じ結果をもたらすと述べています。これは、最適化のためにリソースを割り当てる最善の方法を予測する際の成功率が50%であることを意味します。最適化を誤って適用した場合の短期的および長期的なコストを考えると、これは実際に信頼できる非常に良いレートではありません。

0
JacquesB