オブジェクト指向は本当にアルゴリズムのパフォーマンスに影響しますか?


14

オブジェクト指向は、多くのアルゴリズムを実装する上で非常に役立ちました。ただし、オブジェクト指向言語は「簡単な」アプローチをガイドすることがあり、このアプローチが常に良いものかどうかは疑問です。

オブジェクト指向は、アルゴリズムを高速かつ簡単にコーディングするのに非常に役立ちます。しかし、このOOPは、パフォーマンスに基づいたソフトウェアにとって不利なものになる可能性があります。つまり、プログラムの実行速度です。

たとえば、グラフノードをデータ構造に格納することは、最初は「簡単」に思えますが、Nodeオブジェクトに多くの属性とメソッドが含まれている場合、アルゴリズムが遅くなる可能性はありますか?

言い換えれば、多くの異なるオブジェクト間の多くの参照、または多くのクラスの多くのメソッドを使用すると、「重い」実装になりますか?


1
かなり奇妙な質問です。OOPがアーキテクチャのレベルでどのように役立つかを理解できます。しかし、通常、アルゴリズムの実装レベルは、OOPが意味するものとはまったく異なる抽象化に基づいて構築されます。そのため、OOPアルゴリズムの実装にとってパフォーマンスが最大の問題ではない可能性があります。パフォーマンスに関しては、OOPでは、単一の最大のボトルネックは通常、仮想呼び出しに関連しています。
SKロジック

@ SK-logic>オブジェクト指向は、ポインターによってエブリシングを操作する傾向があり、これはメモリ割り当て側のより重要なワークロードを意味し、非ローカライズデータはCPUキャッシュにない傾向があり、最後になりますが、多くの間接を意味しますCPUパイプラインにとって致命的な分岐(仮想関数)。OOは良いことですが、場合によっては確かにパフォーマンスコストがかかる可能性があります。
deadalnix

グラフ内のノードに100個の属性がある場合、実際の実装に使用されるパラダイムに関係なく、それらを格納する場所が必要になります。一般的に、単一のパラダイムがどのようにこれにエッジを持っているかわかりません。@deadalnix:一定の要因は、特定の最適化を難しくするために悪化する可能性があります。しかし、私は不可能ではなく難しいことを言います-たとえば、PyPyはオブジェクトをタイトループでアンボックス化でき、JVMは仮想関数呼び出しを永遠にインライン化しています。

Pythonはアルゴリズムのプロトタイピングに適していますが、一般的なアルゴリズムを実装するときにクラスを必要としない場合がよくあります。
ジョブ

1
ソフトウェア業界では、これらの日見過ごされている何か、両方のアルゴリズムを持つオブジェクト指向の関係については+1、およびアカデミー...
umlcat

回答:


16

カプセル化のため、オブジェクトの方向によって特定のアルゴリズムの最適化が妨げられる場合があります。2つのアルゴリズムは特にうまく機能しますが、OOインターフェースの背後に隠れている場合、それらの相乗効果を使用する可能性は失われます。

数値ライブラリを見てください。それらの多くは(60年代または70年代に書かれたものだけでなく)OOPではありません。それには理由があります-数値アルゴリズムはmodules、インターフェイスとカプセル化を備えたオブジェクト指向の階層としてよりも、分離されたセットとしての方がうまく機能します。


2
その主な理由は、C ++のみが式テンプレートを使用してOOバージョンを効率的にすることを考え出したことです。
DeadMG

4
最新のC ++ライブラリ(STL、Boost)を見てください-それらもまったくOOPではありません。パフォーマンスだけではありません。通常、アルゴリズムはOOPスタイルでうまく表現できませんでした。汎用プログラミングのようなものは、低レベルのアルゴリズムにより適しています。
SKロジック

3
なに?私はquant_devやSK-logicとは異なる惑星から来たと思います。いいえ、別の宇宙。さまざまな物理法則とすべて。
マイクナキス

5
@MikeNakis:視点の違いは、(1)特定の計算コードがOOPからの人間の可読性の点でメリットがあるかどうか(数値レシピではありません)です。(2)OOPクラスの設計最適なデータ構造とアルゴリズムと一致するかどうか(私の答えを参照)。(3)インダイレクションの各レイヤーが十分な「価値」を提供するかどうか(機能呼び出しごとの作業完了またはレイヤーごとの概念の明確さ)がオーバーヘッドを正当化します(インダイレクション、関数呼び出し、レイヤー、またはデータコピーのため)。(4)最後に、コンパイラ/ JIT /オプティマイザの高度化が制限要因です。
rwong

2
@MikeNakis、どういう意味ですか?STLはOOPライブラリだと思いますか?とにかく、汎用プログラミングはOOPにはうまくいきません。そして言うまでもなく、OOPは非常に狭いフレームワークであり、ごく少数の実用的なタスクにのみ適しており、他のものには異質です。
SKロジック

9

パフォーマンスを決定するものは何ですか?

基本:データ構造、アルゴリズム、コンピューターアーキテクチャ、ハードウェア。さらにオーバーヘッド。

OOPプログラムは、CS理論で最適と見なされるデータ構造とアルゴリズムの選択と正確一致するように設計できます。最適なプログラムと同じパフォーマンス特性に加えて、いくらかのオーバーヘッドがあります。通常、オーバーヘッドは最小限に抑えることができます。

ただし、基本的なことを考慮せずにOOPの懸念のみで最初に設計されたプログラムは、最初は最適ではない可能性があります。準最適性は、リファクタリングによって除去できる場合があります。時々そうではありません-完全な書き換えが必要です。

警告:ビジネスソフトウェアのパフォーマンスは重要ですか?

はい。ただし、市場投入までの時間(TTM)は、桁違いに重要です。ビジネスソフトウェアは、複雑なビジネスルールに対するコードの適応性に重点を置いています。パフォーマンス測定は、開発ライフサイクル全体で実施する必要があります。(セクション:最適なパフォーマンスの意味を参照してください)市場性のある拡張のみを行い、以降のバージョンでは徐々に導入する必要があります。

最適なパフォーマンスとはどういう意味ですか?

一般に、ソフトウェアのパフォーマンスに関する問題は、「より高速なバージョンが存在する」ことを証明するために、より高速なバージョンが最初に存在する必要があることです(つまり、それ以外の証拠はありません)。

時には、より高速なバージョンが最初に別の言語またはパラダイムで見られます。これは、他の言語やパラダイムの劣等の判断ではなく、改善のヒントとしてとるべきです。

最適なパフォーマンスの検索を妨げる可能性があるのに、なぜOOPを行うのですか?

OOPは、「スペース」と「実行」にオーバーヘッドを導入しますが、代わりに「作業性」を改善し、コードのビジネス価値を改善します。これにより、さらなる開発と最適化のコストが削減されます。@MikeNakisを参照してください。

OOPのどの部分が最初の最適ではない設計を促進する可能性がありますか?

OOPの各部分は、(i)シンプルさ/直感性を促進し、(ii)基礎の代わりに口語的なデザイン手法を使用し、(iii)同じ目的の複数の調整された実装を阻止します。

  • 接吻
  • ヤグニ
  • ドライ
  • 基礎に平等な考えを与えないオブジェクト設計(CRCカードなど)

いくつかのOOPガイドラインの厳密な適用(カプセル化、メッセージの受け渡し、1つのことをうまく行う)は、実際には最初はコードが遅くなります。パフォーマンス測定は、これらの問題の診断に役立ちます。データ構造とアルゴリズムが理論的に予測された最適設計と整合している限り、オーバーヘッドは通常最小限に抑えることができます。

OOPオーバーヘッドの一般的な緩和策は何ですか?

前述のように、設計に最適なデータ構造を使用します。

一部の言語は、実行時のパフォーマンスを回復できるコードのインライン化をサポートしています。

パフォーマンスを犠牲にせずにOOPを採用するにはどうすればよいですか?

OOPと基礎の両方を学び、適用します。

OOPを厳守すると、より高速なバージョンを書くことができなくなる可能性があります。より高速なバージョンは、最初からしか書けない場合があります。これが、異なるアルゴリズムとパラダイム(OOP、汎用、機能、数学、スパゲッティ)を使用して複数のバージョンのコードを記述し、最適化ツールを使用して各バージョンが観察された最大パフォーマンスに近づくようにするのに役立つ理由です。

OOPの恩恵を受けないタイプのコードはありますか?

([@quant_dev]、[@ SK-logic]、および[@MikeNakis]間の議論から拡大)

  1. 数学に由来する数値レシピ。
    • 数学の方程式と変換自体はオブジェクトとして理解できます。
    • 効率的な実行可能コードを生成するには、非常に高度なコード変換技術が必要です。素朴な(「ホワイトボード」)実装のパフォーマンスはひどいものになります。
    • しかし、今日の主流のコンパイラはそうすることができません。
    • 専用ソフトウェア(MATLABやMathematicaなど)には、一部のサブ問題に対して効率的なコードを生成できるJITとシンボリックソルバーの両方があります。これらの特殊なソルバーは、それ自体がOOP設計の恩恵を受ける特別な目的のコンパイラー(人間が読み取れるコードと機械で実行可能なコードの間のメディエーター)として見ることができます。
    • 各サブ問題には、独自の「コンパイラ」と「コード変換」が必要です。したがって、これは非常に活発なオープン研究分野であり、毎年新しい結果が現れています。
    • 研究には時間がかかるため、ソフトウェアライターは紙上で最適化を実行し、最適化されたコードをソフトウェアに転写する必要があります。転写されたコードは実際には理解できない場合があります。
  2. 非常に低レベルのコード。
      *

8

それは、実際にはコンテナのようなオブジェクトの向きではありません。ビデオプレーヤーにピクセルを保存するために二重リンクリストを使用した場合、問題が発生します。

ただし、正しいコンテナを使用する場合、std :: vectorが配列より遅い理由はありません。また、すべての一般的なアルゴリズムが既に作成されているため(専門家によって)、ホームロール配列コードよりもおそらく高速です。


1
コンパイラは準最適であるため(またはプログラミング言語の規則により、特定の仮定や最適化を利用することは禁じられているため)、実際には除去できないオーバーヘッドがあります。また、ベクトル化などの特定の最適化には、OOPが強化または妨害する可能性のあるデータ編成要件(構造体配列ではなく配列構造体など)があります。(私は最近std :: vector最適化タスクに取り組んだ。)
rwong

5

OOPは明らかに良いアイデアであり、他の良いアイデアと同様に使いすぎる可能性があります。私の経験では、使いすぎです。パフォーマンスが低下し、保守性が低下します。

仮想関数を呼び出すオーバーヘッドとは関係がなく、オプティマイザー/ジッターが行うこととはあまり関係ありません。

それは、最高のbig-Oパフォーマンスを持ちながら、非常に悪い一定の要因を持っているデータ構造に関係しています。これは、アプリにパフォーマンスを制限する問題がある場合は別の場所にあるという前提で行われます。

これが明示する1つの方法は、1秒あたりの新規実行回数です。これは、O(1)パフォーマンスがあると想定されますが、数百から数千の命令を実行できます(一致する削除またはGC時間を含む)。これは、使用済みオブジェクトを保存することで軽減できますが、コードの「クリーンさ」が低下します。

それが明示するもう1つの方法は、プロパティ関数、通知ハンドラー、基本クラス関数の呼び出し、一貫性を維持するために存在するすべての種類の地下関数呼び出しの作成を奨励​​する方法です。一貫性を維持するために、それらは限られた成功を収めていますが、無駄なサイクルで大成功しています。プログラマーは正規化されたデータの概念を理解していますが、データベース設計にのみ適用する傾向があります。少なくとも部分的にはOOPが必要がないことを伝えているため、データ構造設計には適用されません。オブジェクトにモディファイドビットを設定するのと同じくらい簡単なことは、そのコードに値するクラスがモディファイドコールを取得してそれを保存するだけではないため、データ構造を介して実行される更新の津波につながる可能性があります。

おそらく、指定されたアプリのパフォーマンスは、書かれているとおりに問題ないでしょう。

一方、パフォーマンスの問題がある場合は、ここでチューニングのを示します。これは多段階のプロセスです。各段階で、特定のアクティビティの大部分が時間を占めており、より高速なものに置き換えることができます。(「ボトルネック」とは言いませんでした。これらはプロファイラーが見つけるのが得意な種類ではありません。)このプロセスでは、高速化を実現するために、データ構造の大規模な置換が必要になることがよくあります。多くの場合、そのデータ構造が存在するのは、推奨されるOOPプラクティスだからです。


3

理論的には、処理速度が低下する可能性がありますが、それでも低速アルゴリズムではなく、実装が低速になります。実際には、オブジェクト指向により、さまざまなwhat-ifシナリオを試す(または将来アルゴリズムを再検討する)ことができます。したがって、アルゴリズムの改善を行うことができます。タスクが困難になるためです。(本質的に全体を書き直す必要があります。)

たとえば、さまざまなタスクとエンティティをクリーンカットオブジェクトに分割することで、後で簡単にアクセスできるようになります。たとえば、いくつかのオブジェクトの間にキャッシュ機能を埋め込むことができます。倍の改善。

一般に、低レベル言語(または高レベル言語での巧妙なトリック)を使用して達成できる改善のタイプは、一定の(線形の)時間改善を提供しますが、これはビッグオー表記の観点からはわかりません。アルゴリズムの改善により、非線形の改善を達成できる場合があります。それは貴重です。


1
+1:スパゲッティとオブジェクト指向コード(または明確に定義されたパラダイムで記述されたコード)の違いは次のとおりです。書き換えられた優れたコードの各バージョンは、問題に新しい理解をもたらします。書き直されたスパゲッティの各バージョンは、洞察をもたらしません。
rwong

@rwongはこれ以上説明できませんでした;-)
umlcat

3

しかし、このOOPは、パフォーマンスに基づいたソフトウェアにとって不利なものになる可能性があります。つまり、プログラムの実行速度です。

多くの場合はい!!! だが...

言い換えれば、多くの異なるオブジェクト間の多くの参照、または多くのクラスの多くのメソッドを使用すると、「重い」実装になりますか?

必ずしも。これは言語/コンパイラに依存します。たとえば、仮想関数を使用しない場合、最適化C ++コンパイラは、多くの場合、オブジェクトのオーバーヘッドをゼロに押し下げます。上のラッパーを書くようなことをすることができますintそこにまたはこれらの単純な古いデータ型を直接使用するのと同じくらい高速に動作する単純な古いポインターにスコープ付きスマートポインターを。

Javaのような他の言語では、オブジェクトに多少のオーバーヘッドがあります(多くの場合非常に小さいことがよくありますが、非常に小さなオブジェクトでまれに天文学的です)。例えば、Integerよりもかなり低効率があるint(64ビット上の4とは対照的に16のバイトを要します)。しかし、これは単なる露骨な無駄やそのようなものではありません。これと引き換えに、Javaは、すべての単一のユーザー定義型に対するリフレクションのようなもの、およびとしてマークされていない関数をオーバーライドする機能を提供しますfinal

しかし、最良のシナリオを考えてみましょう。オブジェクトインターフェイスをゼロオーバーヘッドまで最適化できる最適化C ++コンパイラです。それでも、OOPはしばしばパフォーマンスを低下させ、ピークに達するのを防ぎます。それは完全なパラドックスのように聞こえるかもしれません。問題は次のとおりです。

インターフェイス設計とカプセル化

問題は、コンパイラがオブジェクトの構造をゼロオーバーヘッドまで押しつぶせる場合でも(少なくともC ++コンパイラの最適化に当てはまる場合がほとんどです)、きめの細かいオブジェクトのカプセル化とインターフェイス設計(および依存関係の蓄積)により、大衆によって集約されることを目的とするオブジェクトの最も最適なデータ表現(パフォーマンスが重要なソフトウェアの場合が多い)。

次の例をご覧ください。

class Particle
{
public:
    ...

private:
    double birth;                // 8 bytes
    float x;                     // 4 bytes
    float y;                     // 4 bytes
    float z;                     // 4 bytes
    /*padding*/                  // 4 bytes of padding
};
Particle particles[1000000];     // 1mil particles (~24 megs)

メモリアクセスパターンは、これらのパーティクルを単純に順番にループし、各フレームの周りを繰り返し移動し、画面の隅から跳ね返して結果をレンダリングするとします。

birth粒子が連続して凝集している場合、メンバーを適切に位置合わせするために必要な、明白な4バイトのパディングオーバーヘッドが既に見られます。アライメントに使用されるデッドスペースにより、すでにメモリーの約16.7%が無駄になっています。

最近はギガバイトのDRAMがあるため、これは無意味に思えるかもしれません。しかし、今日の最も恐ろしいマシンでさえ、CPUキャッシュ(L3)の最も遅くて最大の領域になると、たった8メガバイトしかありません。そこに収まらないほど、DRAMアクセスの繰り返しという観点からはより多くのお金を払うことになり、速度は低下します。突然、メモリの16.7%を無駄にすることは、ささいなことのようには思えません。

フィールドの配置に影響を与えることなく、このオーバーヘッドを簡単に排除できます。

class Particle
{
public:
    ...

private:
    float x;                     // 4 bytes
    float y;                     // 4 bytes
    float z;                     // 4 bytes
};
Particle particles[1000000];     // 1mil particles (~12 megs)
double particle_birth[1000000];  // 1mil particle births (~8 bytes)

メモリを24メガから20メガに削減しました。シーケンシャルアクセスパターンでは、マシンはこのデータをかなり速く消費します。

しかし、このbirthフィールドをもう少し詳しく見てみましょう。パーティクルが生まれる(作成される)開始時間を記録するとしましょう。パーティクルが最初に作成されたときにのみフィールドにアクセスし、画面上のランダムな場所でパーティクルが死んで生まれ変わるかどうかを10秒ごとに想像してください。その場合、birthコールドフィールドです。パフォーマンス重視のループではアクセスされません。

その結果、パフォーマンスが重視される実際のデータは20メガバイトではなく、実際には12メガバイトの連続したブロックになります。頻繁にアクセスする実際のホットメモリは、そのサイズの半分に縮小されています!元の24メガバイトソリューションの大幅な高速化を期待してください(測定する必要はありません-すでにこの種の作業を1000回行っていますが、疑問がある場合はお気軽に)。

しかし、ここで行ったことに注意してください。このパーティクルオブジェクトのカプセル化を完全に解除しました。その状態は、Particle型のプライベートフィールドと別の並列配列に分割されるようになりました。そして、それがきめ細かいオブジェクト指向設計の邪魔になるところです。

単一の粒子、単一のピクセル、単一の4コンポーネントベクトル、場合によってはゲーム内の単一の「作成」オブジェクトなど、単一の非常に粒度の高いオブジェクトのインターフェース設計に限定すると、最適なデータ表現を表現できません。チーターが2平方メートルの小さな島に立っている場合、チーターの速度は無駄になります。これは、パフォーマンスの観点から非常にきめ細かいオブジェクト指向設計がよく行うことです。データ表現を次善の性質に限定します。

これをさらに進めるために、パーティクルを移動しているだけなので、実際には3つの別々のループでx / y / zフィールドにアクセスできるとしましょう。その場合、8つのSPFP操作を並行してベクトル化できるAVXレジスターを備えたSoAスタイルのSIMD組み込み関数の恩恵を受けることができます。しかし、これを行うには、次の表現を使用する必要があります。

float particle_x[1000000];       // 1mil particle X positions (~4 megs)
float particle_y[1000000];       // 1mil particle Y positions (~4 megs)
float particle_z[1000000];       // 1mil particle Z positions (~4 megs)
double particle_birth[1000000];  // 1mil particle births (~8 bytes)

パーティクルシミュレーションを使用して飛行していますが、パーティクルデザインに何が起こったかを確認します。これは完全に取り壊されており、4つの並列配列を検討していますが、それらをすべて集約するオブジェクトはありません。私たちのオブジェクト指向Particleデザインはさよならを失いました。

これは、ユーザーが速度を要求するパフォーマンス重視の分野で働いているときに何度も起こりました。これらの小さなオブジェクト指向設計は取り壊す必要があり、カスケード破損により、より高速な設計に向けて低速の非推奨戦略を使用する必要がしばしばありました。

解決

上記のシナリオでは、オブジェクト指向のきめ細かい設計でのみ問題が発生します。そのような場合、SoA担当者、ホット/コールドフィールド分割、シーケンシャルアクセスパターンのパディング削減の結果として、より効率的な表現を表現するために、構造を破壊する必要が生じることがよくあります(パディングはランダムアクセスのパフォーマンスに役立つことがありますAoSの場合のパターンですが、ほとんどの場合、シーケンシャルアクセスパターンの妨げになります)など。

それでも、私たちが決めた最終的な表現を取り、それでもオブジェクト指向インターフェースをモデル化することができます。

// Represents a collection of particles.
class ParticleSystem
{
public:
    ...

private:
    double particle_birth[1000000];  // 1mil particle births (~8 bytes)
    float particle_x[1000000];       // 1mil particle X positions (~4 megs)
    float particle_y[1000000];       // 1mil particle Y positions (~4 megs)
    float particle_z[1000000];       // 1mil particle Z positions (~4 megs)
};

今は元気です。好きなオブジェクト指向のグッズをすべて入手できます。チーターは、可能な限り速く走る国全体を持っています。私たちのインターフェース設計は、もはや私たちをボトルネックコーナーに閉じ込めません。

ParticleSystem潜在的に抽象的であり、仮想関数を使用することさえできます。今では意味がありません。私たちは、パーティクルごとのレベルではなく、パーティクルコレクションレベルオーバーヘッドを払っています。オーバーヘッドは、個別のパーティクルレベルでオブジェクトをモデリングした場合の1/100万分の1です。

したがって、これは、重い負荷を処理し、あらゆる種類のプログラミング言語(この手法はC、C ++、Python、Java、JavaScript、Lua、Swiftなどに役立つ)を処理する真のパフォーマンスクリティカルな領域のソリューションです。また、「早期最適化」というラベルを簡単に付けることはできません。これは、インターフェースの設計アーキテクチャの関連しているため、。単一のパーティクルをオブジェクトとしてモデル化するコードベースを作成することはできません。Particle'sパブリックインターフェイスを使用してから、後で気が変わります。レガシーコードベースを最適化するために呼び出されたとき、私は多くのことをしました。これは、大きな負荷が予想される場合、事前に設計する方法に理想的に影響します。

多くのパフォーマンスに関する質問、特にオブジェクト指向の設計に関する質問では、この答えを何らかの形で繰り返します。オブジェクト指向の設計は、最高のパフォーマンス要件を満たすことができますが、それに対する考え方を少し変更する必要があります。そのチーターにできるだけ速く走らせるための余地を与えなければなりません。また、状態をほとんど格納しない小さなオブジェクトを設計する場合、それはしばしば不可能です。


素晴らしい。これは、OOPと高性能の要求を組み合わせるという点で、私が実際に探していたものです。私は本当にそれがもっと支持されない理由を本当に理解できません。
pbx

2

はい。アルゴリズム指向レベルと実装レベルの両方で、高性能プログラミングに関しては、オブジェクト指向マインドセットは間違いなくニュートラルまたはネガティブです。OOPがアルゴリズム分析に置き換わると、実装が時期尚早になる可能性があり、最低レベルでは、OOP抽象化を脇に置く必要があります。

この問題は、OOPが個々のインスタンスについて考えることに重点を置いていることに起因しています。アルゴリズムについてのOOPの考え方は、特定の値のセットについて考え、それをそのように実装することだと言ってもいいと思います。それがあなたの最高レベルの道であるなら、あなたはビッグOの利益につながる変換または再構築を実現する可能性は低いです。

アルゴリズムレベルでは、より大きな全体像と、ビッグOゲインにつながる値間の制約または関係についてよく考えています。例としては、OOPの考え方には、「整数の連続範囲の合計」をループから(max + min) * n/2

実装レベルでは、コンピューターはほとんどのアプリケーションレベルのアルゴリズムに対して「十分に高速」ですが、低レベルのパフォーマンスクリティカルなコードでは、局所性についてかなり心配します。繰り返しますが、OOPは個々のインスタンスとループを通過する1つの値について考えることに重点を置いています。高性能なコードでは、単純なループを作成する代わりに、ループを部分的に展開し、複数のロード命令を最上部にグループ化し、それらをグループに変換してからグループに書き込むことができます。その間ずっと、中間計算に注意を払っていると思いますが、非常に大きなことはキャッシュとメモリアクセスです。OOP抽象化が無効になった問題。そして、従えば、誤解を招く可能性があります。このレベルでは、マシンレベルの表現について知って、考える必要があります。

Intelのパフォーマンスプリミティブのようなものを見ると、文字通り何千もの高速フーリエ変換の実装があり、それぞれが特定のデータサイズとマシンアーキテクチャに合わせて調整されています。(興味深いことに、これらの実装の大部分はマシン生成であることがわかりましたMarkusPüschelAutomatic Performance Programming

もちろん、ほとんどの答えが述べているように、ほとんどの開発では、ほとんどのアルゴリズムでは、OOPはパフォーマンスとは無関係です。「早すぎるペシマイズ」や多くの非ローカルコールを追加しない限り、thisポインタはここにもそこにもありません。


0

その関連し、しばしば見落とされます。

簡単な答えではなく、何をしたいかによって異なります。

一部のアルゴリズムは、単純な構造化プログラミングを使用してパフォーマンスが向上しますが、他のアルゴリズムは、オブジェクト指向を使用した方が優れています。

オブジェクト指向の前に、多くの学校は、構造化プログラミングを使用したアルゴリズム設計(教育)を教えています。今日、多くの学校は、アルゴリズムの設計とパフォーマンスを無視して、オブジェクト指向プログラミングを教えています。

もちろん、構造化プログラミングを教える学校は、アルゴリズムをまったく気にしませんでした。


0

パフォーマンスはすべて、最終的にCPUとメモリのサイクルに帰着します。ただし、OOPメッセージングおよびカプセル化のオーバーヘッドと、よりオープンなプログラミングセマンティックのオーバーヘッドの割合の差は、アプリケーションのパフォーマンスに顕著な差をもたらすのに十分な割合である場合とそうでない場合があります。アプリがディスクまたはデータキャッシュミスにバインドされている場合、OOPオーバーヘッドはノイズで完全に失われる可能性があります。

ただし、リアルタイムの信号処理と画像処理、およびその他の数値計算にバインドされたアプリケーションの内部ループでは、その差はCPUサイクルとメモリサイクルのかなりの割合になる可能性があり、OOPオーバーヘッドの実行コストがはるかに高くなる可能性があります。

特定のOOP言語のセマンティクスは、コンパイラーがそれらのサイクルを最適化するための十分な機会を公開する場合としない場合があります。


0

優れたオブジェクト指向設計は、アプリケーションを大幅に高速化するのに役立ちました。Aはアルゴリズム的な方法で複雑なグラフィックを生成する必要がありました。Microsoft Visioの自動化を通じてそれを行いました。私は働いたが、信じられないほど遅かった。幸いなことに、私はロジック(アルゴリズム)とVisioの間に余分なレベルの抽象化を挿入していました。Visioコンポーネントは、インターフェイスを介してその機能を公開しました。これにより、低速のコンポーネントを、少なくとも50倍高速な別のSVGファイルを作成するものに簡単に置き換えることができました!明確なオブジェクト指向のアプローチがなければ、アルゴリズムとビジョンコントロールのコードが絡み合ってしまい、変更が悪夢に変わっていただろう。


OO Designに手続き型言語、またはOO Design&OOプログラミング言語を適用したということですか?
umlcat

私はC#アプリケーションについて話しています。設計と言語はどちらもオブジェクト指向です。言語のオブジェクト指向性がパフォーマンスの小さなヒット(仮想メソッド呼び出し、オブジェクト作成、インターフェイス経由のメンバーアクセス)をもたらすため、オブジェクト指向設計ははるかに高速なアプリケーションの作成に役立ちました。私が言いたいのは、オブジェクト指向(言語とデザイン)によるパフォーマンスヒットを忘れることです。数百万回の反復を伴う重い計算を行わない限り、オブジェクト指向は害を与えません。通常、多くの時間を失うのはI / Oです。
オリビエジャコット-デスコンベス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.