web-dev-qa-db-ja.com

モジュール化とパフォーマンスのメリット

私の経験からソフトウェアをモジュール化するとパフォーマンスが低下するようです。オーバーヘッドのほとんどはモジュールの通信、計算、ストレージの冗長性であり、アプリケーションによっては拡張の程度が大きくなるか、コンパイラーによって最適化されます。

だから私は例えばの利点を考えてきましたマイクロサービスと、保守が難しい大規模システム。

モジュール化を維持するものと、設計プロセスで1つのシステムとして維持するものを選択するときに使用するいくつかの良い基準は何ですか?

3
user99355

モジュールは変更を分離する必要があります。

モジュールの境界は、システムの他の部分に伝播する設計変更に対するファイアウォールとして機能する必要があります。

したがって、モジュールは設計決定を完全にカプセル化する必要があります。その決定を変更しても、そのモジュールにのみ影響が及ぶはずです。

したがって、できる限り多くの設計上の決定をモジュールに分離するよう努めます。そうすれば、ヒットが変更されたときにすべてを書き直す必要はありません。

速度がより重要であり、変化があなたを打つことは決してないと信じているなら、ソフトウェアで問題を解決するのをやめてください。はんだごてを使用してください。

8
candied_orange

モジュール化を維持するものと、設計プロセスで1つのシステムとして維持するものを選択するときに使用するいくつかの良い基準は何ですか?

私は鳥瞰図からシステムを整理する方法でそのような選択を考慮せず、パストレーサー、リアルタイムレンダラー、流体ダイナミクスを備えたVFXのかなりパフォーマンスが重要な領域(組み込みほどタイトではない)で作業しています、パーティクルシム、物理学、大規模シーンのすべてのキャラクターに適用されるインバースキネマティクス、エンドレスメッシュアルゴリズム、インタラクティブスカルプティング、テクスチャペイントなど。

これらすべてにもかかわらず、パフォーマンスを優先してモジュール性または抽象化を妥協する必要性を見つけたことは一度もありませんが、デザインに影響を与えるデザインレベルのパフォーマンスの懸念が時々ありますが、これらの品質を犠牲にする方法ではありません。

[...]オーバーヘッドのほとんどは、モジュールの通信、計算、ストレージの冗長性であり、アプリケーションに応じて、程度の差はありますが、コンパイラーによって最適化できます。

次に、通信の頻度を減らします。ソーダ缶に追加のペニーをいくらか払うのが比較的高額な場合は、一度に1缶のソーダを購入しないでください。 24パックまたは100万缶のソーダを一度に購入し、購入のための追加のペニーは絶対に取るに足らないものです。

それが私にとっての設計レベルの問題です(これをできるだけ早く効率的に実装したいという欲求と混同してはなりません)。それは、単一のピクセルで実行する通信操作の細かいレベルでリアルタイムにピクセルを通過することを目的とした画像合成ソフトウェアをモジュール化または抽象化しないようなものです。その場合、動的ディスパッチの追加のオーバーヘッドと課す最適化の障壁(たとえば、コンパイル時の情報がないためにコンパイラーがインライン化できないなど)は途方もないオーバーヘッドであり、さらに、モジュールのピクセルインターフェイスへの依存関係により、アーキテクチャの設計全体を再検討しないと、パフォーマンスが低下する可能性のあるボトルネックを効果的に最適化できない設計コーナー。代わりに画像全体のレベルで抽象化/モジュール化し(多くの場合、数百万ピクセルの集合)、それらのコストは絶対に簡単になり、コードの作成や維持がはるかに困難になり、モジュール性に妥協する必要はありません。

そして、それは通常、モジュール化するかどうかではなく、モジュールの操作をどの程度細かくすべきかという点で、私が最近デザインについて心配していることです。通信につながるオーバーヘッドのコストを単純化するのに十分な機能を備えた関数はどれもあるので、パフォーマンスが強力な設計レベルの要件であると予想される領域での私の目標は、後からコストのかかる設計変更の確率を減らすことです。関数が実行するのに十分な量の作業を持ち、モジュールを呼び出すいくつかのタイトなループ内で比較的些細な作業を行うためだけに外部から10億回呼び出されないようにするため。そして、それは、設計全体をやり直す必要なく、後からの測定、事後測定での実装を最適化するために十分な余地を残すことを目標としています。粗雑に言えば、ループのコードをモジュールの中に置くのではなく、モジュールの小さな関数を外の世界から無数の回数呼び出すだけです。

ニュアンス

これはかなり微妙になっていますが、「一括処理の設計」の考え方の詳細をいくつか説明します。たとえば、モジュールの呼び出し元から提供された述語を満たす要素で動作するモジュールのパブリックインターフェイスを設計する場合、前もってパフォーマンスが非常に重要であると思われるときは、述語の設計でなくてもかまいません。一度に1つの要素を操作します。たとえば、スタックから渡された64要素を一度に操作して、述部を満たす要素に設定されたビットで64ビット整数を返すことができます。これにより、呼び出しのオーバーヘッドが、通常の場合の1/64に削減されます。述語がより大きな配列で動作し、より大きなビットセットを返す場合、さらに削減できます。これらの配列を構築するコスト(スタックまたは時間的局所性の高い他のメモリにそれらを格納する場合)は、通常、簡単で安価です。要素ごとの動的ディスパッチ/呼び出しオーバーヘッドよりも。

Unitの概念とHumanOrcElfのようなサブタイプを持つ大規模なリアルタイムビデオゲームをお持ちの場合は、一度に1つのUnitを処理するインターフェイスとモジュールを設計します。抽象コレクションUnitsインターフェースを設計し、HumansElvesOrcsなどの具象型を、これらのコレクション全体を操作する抽象関数で作成できます。一度に。以前はゲーム開発者が、多態性ベースポインターのソートなどのあらゆる種類のループをジャンプして、動的ディスパッチと空間的局所性に関する分岐予測を改善し、カスタムアロケーターを実装して、こうした細かいレベルでこれらのものを設計して作成したボトルネックを回避しようとしているのを見ますが、ホットスポットに応答して、開発者が細かい微調整でひどく深くならないはるかに単純なソリューションは、より粗い集計レベルで設計するだけです(これにより、システムを以前と同じ数のモジュールに分解できますが、今では、それぞれの機能でやるべきことはたくさんあります。

1
Dragon Energy