機能を使用すると効率(速度)が外的に損なわれますか? それが可読性と 効率の間のカットオフをどのように把握することができますか?
パフォーマンスのために、まともなオプティマイザに対する直接関数呼び出しのオーバーヘッドは、一般的に考慮しません。そうでない場合、99.9%のシナリオでは無視できるオーバーヘッドです。パフォーマンス重視の分野でも同様です。レイトレーシング、メッシュ処理、画像処理などの分野で働いていますが、参照の局所性、効率的なデータ構造、並列化、ベクトル化とは対照的に、関数呼び出しのコストは通常優先順位リストの一番下にあります。マイクロ最適化を行っている場合でも、ダイレクト関数呼び出しのコストよりもはるかに大きな優先順位があり、マイクロ最適化を行っている場合でも、オプティマイザが実行する最適化をあなたが実際にアセンブリコードを書いている場合を除いて、それと戦い、手でそれをしようとします。
もちろん、いくつかのコンパイラでは、インライン関数呼び出しをしない関数や、すべての関数呼び出しに少しオーバーヘッドがあるものもあります。しかし、そのような場合には、これらの言語やインタプリタ/コンパイラを使用する際に、このようなミクロレベルの最適化について心配するべきではないので、比較的無視できると言います。それでも、参照とスレッド効率の局所性を改善するなど、よりインパクトのあるものとは対照的に、優先順位リストの下位に位置することがよくあります。
非常に単純なレジスタ割り当てを使用するコンパイラを使用していて、使用するすべての変数にスタックが流出するような場合は、できるだけ少ない変数を使用して再利用しようとする必要はありませんその傾向を中心にこれは、無視できないオーバーヘッド(例えば、Cylinderの一部をdylibに書き込んで、最も重要な部分に使用する)や、すべてを実行するようなより高度な最適化に焦点を当てた場合に、新しいコンパイラを手に入れることです並行して。
どのように機能を小さくする必要がありますか?明らかに、私はこれまで関数を繰り返さなければならないとすれば、 を作っていましたが、1回は何回ですか? 関数を使用しますか?
これは、私がやや軽くなっていくところです。実際には、メンテナンス性の理由から十分な機能を避けることをお勧めします。少なくともJohn Carmackは、(コードをインライン化し、副作用を理解しやすくするために副作用が発生した場合の過剰な関数呼び出しを避けるために)少なくともいくらかは同意しているようですが、これは間違いありません。
しかし、多くの状態変更を行う場合は、 をすべてインラインで実行すると利点があります。常にあなたがしていることの完全な恐怖を認識して を作成する必要があります。
私は時々meatier機能の側に誤るために良いことができます信じている理由は、変更を行うか、問題を解決するために必要なすべての情報を理解するために簡単な関数よりも理解する方がしばしばありますされているため、 。
論理が80行のインラインコードで構成されている関数、または数十の関数に分散された関数、おそらくはコードベース全体で異なる場所につながる関数を理解するのは簡単ですか?
答えはあまり明確ではありません。当然ながら、例えば、sqrt
やabs
のように、小さな関数が広く使われている場合、読者は関数呼び出しをスキップして、手の後ろが好きであることを十分に知ることができます。しかし、一度しか使用されていない小さなエキゾチックな機能がたくさんある場合、操作全体を理解する能力は、それらを見て、何が起こっているのかについて適切な理解を得る前に、大きな絵の言葉。
Apple Swiftのチュートリアルでは、実際には算術と比較が何をするかを理解するよりも理解しやすいものですから、何を参照するにはあなたが言うことができないシナリオでは、isCandyAmountAcceptable
は私のための十分な情報であり、何が金額を受け入れるかを正確に把握する必要があります。その後、あなたはコード内の異なる場所にジャンプする必要はありませんので、本の類推が原因ブックの他のページへの読者を参照(...
// Determine if candy amount is acceptable.
if (candyCount % bandMemberCount == 0)
...
:代わりに、私は実際に簡単なコメントを好むだろう読者は常にページ間を行き来する必要があります)。もちろん、このisCandyAmountAcceptable
の機能の背後にあるアイデアは、キャンディーの量を容認できるものにするような詳細については心配する必要はありませんが、実際にはあまりにも頻繁に、最適にコードをデバッグしたり、コードを変更したりする必要があります。コードをデバッグしたり変更したりする必要がない場合は、どのように記述するかは問題になりません。私たちが気にしているすべてのものについて、バイナリコードで記述することさえできます。しかし、将来的にデバッグしたり変更したりするように書かれているのであれば、読者がたくさんのフープを飛ばさなければならないことを避けるのが役に立ちます。これらのシナリオでは、細部はしばしば重要です。
時には大きな絵をパズルピースの中で最も細かいものに分けることで、大きな絵を理解するのに役立つことはありません。バランスのとれた行為ですが、特定のタイプの開発者は、システムを過度に細かく分割し、メンテナンスの問題をそのように見極めることで誤りを犯す可能性があります。これらのタイプは依然として有望なエンジニアであり、バランスをとるだけです。もう一つの極端なのは、500行の関数を書き、リファクタリングを考慮しなくても極端なものです。しかし、私はあなたが以前のカテゴリに適合していると思うし、実際には、ちょっとだけ、パズルピースを健康的なサイズ(あまりにも小さくない、あまりにも大きくない)に保つためにちょっとした機能の面で間違っていることをお勧めします。
コードの重複と依存関係の最小化の間にはバランスの取れた動作があります。交換が数百万行の複雑な数学ライブラリへの依存であれば、複写された数学コードの数十行を削って画像ライブラリを理解することは必ずしも容易ではありません。このような場合、外部の依存関係を避けるために数学関数を複製する代わりに、別の場所に配布するのではなく、その複雑さを分離することを選択すると、画像ライブラリは非常に理解しやすくなり、新しいプロジェクトでの使用と展開も可能になります。
基本的に、効率性のためにどのような時点で可読性を犠牲にしますか?
上記のように、私は小さな画像の可読性と大きな画像の理解度は同義ではないと思います。 2行の関数を読み、それが何をしているのかを知っていて、必要な変更を行うために理解する必要があることを理解することからまだまだ離れていることは本当に簡単です。これらの小さなワンショットの2ライナーの多くは、大きな画像を理解する能力を遅らせることさえできます。
しかし、「理解度と効率」を代わりに使用すると、巨大な入力を処理することが予想される場合には、設計レベルでの前払いと言えます。一例として、カスタムフィルタを備えたビデオ処理アプリケーションは、フレームごとに数百万のピクセルにわたって何度もループすることを知っています。その知識は、何百万ものピクセルにわたって繰り返しループするための効率的な設計を思い付くために利用されるべきである。しかし、それは設計に関して言えば - 大きな中心的な設計変更は遅れて適用するにはコストがかかりすぎるため、他の多くの場所が依存するシステムの中心的な側面に向かっています。
これは、わかりやすいSIMDコードをバットから外して適用しなければならないというわけではありません。これは、設計が、そのような最適化を後見の中で探求するのに十分な呼吸スペースを残すなら、実装の詳細です。このようなデザインは、レベルで抽象化することを意味し、単一のレベルではなく、百万ピクセルのレベルで抽象化することを意味する。IPixel
。これは前もって考慮する価値があることです。
その後、ホットスポットを最適化し、操作がより速く進むようにビジネスニーズが強く認識されている真にクリティカルなケースに対して、ここでは理解しにくいアルゴリズムやマイクロ最適化を使用することができます良いツール(プロファイラー、すなわち)を手にして。ユーザーのケースでは、ユーザーが最も頻繁に行うことに基づいて最適化する操作をガイドし、待ち時間を短くしたいという強い希望を見つけます。プロファイラは、その操作に含まれるコードのどの部分を最適化する必要があるかを正確に案内します。
質問1の答えは、使用している言語と実装(つまり、特定のコンパイラ、インタープリタなど)によって異なります。 – melpomene
関数呼び出しのオーバーヘッドが異なる状況下で重大である場合には、既存の投稿がカバーしていることは確かです。それはiircでもC++のためです。 – Carcigenicate