PLOの華麗さと貧しさ

 

基本クラス、複数の子孫、起動時に設定されたパラメータにより、子孫のうちの1つが使用される。これは、ユニバーサル・プログラムの動作原理としてよく知られている。この場合、プログラムの動作を変更するような if や switch の呼び出しはなく、初期化時に必要な子孫クラスが選択されるだけで、あとはすべてが単純に動作するため、バリエーションがいくつあっても問題ありません。

class CBase{
   private:
   public:
      virtual void Fun(){
      
      }
};

class CClass1:CBase{
   private:
   public:
      void Fun(){
      
      }
};

CClass1 * cl;

void OnInit(){

   cl=new CClass1;

}

しかし...

何種類のバリエーションがあるのでしょうか?妥当な数字?10, 20, 100?100種類のバリアントがあっても、スイッチはOOPよりも高速に動作します。

ここでは、性能比較のためのスクリプトを紹介します。上記のOOPと、関数による単純なスイッチ(しかも2つの関数が呼ばれ、一方の関数呼び出しは 簡単に捨てられる)を比較したものです。

void ff(int z){

      switch(z){
         case 0:
         f0();
         break;

         ...

         case 99:
         f99();
         break;

      }
     
}
その結果(f99を呼び出す)。

ファイル:
test.mq4  9 kb
 
Integer:

何種類のオプションがあるのでしょうか?妥当な数字?10, 20, 100?100個の選択肢があっても、スイッチはOOPよりも高速に動作します。

mqlでは仮想的な「疑似ポインタ」、つまり本質的には実アドレスの内部(隠れた)ハッシュテーブルを参照するハンドルを使用しているので、このような効果が期待できるのは妥当なことです。このようなポインタを解決するためには、直接ポインタアドレッシングをはるかに超える余分な時間がかかります。 測定したわけではありませんが、dotNET言語や他の同様の実装でも、同じポインタの「ボトルネック化」効果が見られると思われます。

本当の」ポインターを持つ言語にはこのような効果はなく、選択肢のリストが大きくなればなるほど、switchはそこで負けてしまうのです。

だから、OOPは本質的に関係ないんです...。

 
MetaDriver:

mqlでは、仮想的な「疑似ポインタ」、つまり実アドレスの内部(隠れた)ハッシュテーブルを参照するハッシュテーブルを使用しているので、このような効果は合理的に期待できます。このようなポインタを解決するためには、直接ポインタアドレッシングをはるかに超える余分な時間がかかります。 測定したわけではありませんが、dotNET言語や他の同様の実装でも、同じポインタの「ボトルネック化」効果が見られると思われます。

本当の」ポインターを持つ言語では、このような効果は発生せず、選択肢のリストが大きくなればなるほど、スイッチは負けてしまいます。

だから、OOPは本質的に関係ないんです...。

コンパイラの問題であることは明らかで、したがって、「正しい」コンパイルを行えば、上記の例の実行 時間は等しくなる。
 
icas:
これは、コンパイラ自体の問題であることは明らかであり、したがって、上記の例が「正しく」コンパイルされれば、実行時間は 等しくなる。
正しさ」という概念はルールに依存するものであり、それゆえ意味がない。;)
 

誤りを端的に指摘すると、f関数は空で、コンパイラによって完全にカットされているのです。つまり、実際には関数の呼び出しが ないのです。また、ff関数がどのような状態に縮退するのか、forループの中でインライン化されてしまい、関数呼び出しすらなくなってしまわないのか、よくわかりません。

一方、仮想メソッドは切り出すことができず、常に呼び出される。その結果、一方ではループが回っているだけで、もう一方では呼び出しがループの中に入っていることになります。

どんなテストでも、まずその正しさを証明し、そのうえで結果に臨まなければならない。

 

ここでは、空でない関数を使ったものを紹介します。

ファイル:
test2.mq4  11 kb
 

ここでは、クラスメソッドよりも 複雑な、ユニークで、しかもスイッチ経由で呼び出される関数をすべて紹介します。

ファイル:
test3.mq4  12 kb
 
Integer:

ここでは、クラスメソッドよりも 複雑な、ユニークで、しかもスイッチ経由で呼び出される関数をすべて紹介します。

なんということでしょう・・・。

インライン化について何かご存知ですか?アグレッシブインライン化については?

単純な関数本体には通常何が起こり、優れた最適化コンパイラはそれをどう処理するのでしょうか?これは1995年の話ではないですよね?

 
MetaDriver:

mqlでは、仮想的な「疑似ポインタ」、つまり実アドレスの内部ハッシュテーブルを参照するハンドルが使われているので、このような効果が期待できるのは妥当なことだと思います。このようなポインタを解決するためには、直接ポインタアドレッシングをはるかに超える余分な時間がかかります。 測定したわけではありませんが、dotNET言語や他の同様の実装でも、同じポインタの「ボトルネック化」効果が見られると思われます。

本当の」ポインターを持つ言語では、そのような効果はなく、選択肢のリストが大きくなればなるほど、スイッチは負けることになります。

だから、OOPは本質的に関係ないんです...。

はい、嬰ハ音記号です:)


7550021(スイッチ)
2250004 (OOP)
7325029 (スイッチ)
2050015 (OOP)
7550049(スイッチ)
2150005 (OOP)
7575031(スイッチ)
2325009 (OOP)
8025038(スイッチ)
2200004 (OOP)
7150027(スイッチ)
2050014 (OOP)
7375029(スイッチ)
2200005 (OOP)
7550022(スイッチ)
1950003 (OOP)
7100021(スイッチ)
2695083 (OOP)
7360033(スイッチ)
2200008 (OOP)
7825029 (スイッチ)
1925010 (OOP)
7325025(スイッチ)
2025006 (OOP)
6850035(スイッチ)
2525014 (OOP)
7750027(スイッチ)
1975007 (OOP)
8195225(スイッチ)
2050004 (OOP)
6950020(スイッチ)
2425006 (OOP)
7275029(スイッチ)
2225015 (OOP)
7050037(スイッチ)
2200007 (OOP)
7375030(スイッチ)

 

どんなテストでも、それが正しいこと、測定すると言っているものを実際に測定していることを証明することから始めます。

上に紹介したものは驚くべき間違いを含んでおり、著者がコンパイルの仕組みやコードがどのように機能するかについて完全に理解していないことを示しています。

 
Renat:

どんなテストでも、それが正しいこと、測定すると言っているものを実際に測定していることを証明することから始めます。

上に紹介したものは驚くべき間違いを含んでおり、著者がコンパイルの仕組みやコードがどのように機能するかについて完全に理解していないことを示しています。

なぜコンパイルの仕組みを理解する必要があるのでしょうか?ただ、良い結果より悪い結果の方が良いと信じているのですか? 重要なのは結果なのです。
理由: