Lo splendore e la povertà dell'OLP

 

Classe base, diversi discendenti, uno dei discendenti viene utilizzato, a seconda dei parametri impostati all'avvio. Questo è un principio ben noto del funzionamento del programma universale. Non importa quante varianti ci possono essere (cioè le classi discendenti), questo caso dovrebbe funzionare molto velocemente perché non ci sono chiamate if e switch per cambiare il funzionamento del programma, solo una volta che la classe discendente richiesta viene selezionata durante l'inizializzazione e poi tutto funziona in modo semplice e diretto.

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

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

CClass1 * cl;

void OnInit(){

   cl=new CClass1;

}

Tuttavia...

Quante varianti diverse ci possono essere? Un numero ragionevole? 10, 20, 100? Anche con 100 varianti, switch funziona più velocemente di OOP.

Ecco uno script per confrontare le prestazioni. Confronta l'OOP di cui sopra e un semplice interruttore con funzioni (e due funzioni sono chiamate, una delle chiamate di funzione può essere facilmente scartata).

void ff(int z){

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

         ...

         case 99:
         f99();
         break;

      }
     
}
I risultati (chiamare f99):

File:
test.mq4  9 kb
 
Integer:

Quante opzioni diverse ci possono essere? Un numero ragionevole? 10, 20, 100? Anche con 100 scelte, switch funziona più velocemente di OOP.

Vorrei mettere in guardia contro le generalizzazioni eccessive: un tale effetto è ragionevole aspettarsi in mql, perché usa "pseudo-puntatori" virtuali - essenzialmente maniglie che fanno riferimento alla tabella hash interna (nascosta) di indirizzi reali. Per risolvere tali puntatori, ci vuole una quantità significativa di tempo extra, ben oltre l'indirizzamento diretto dei puntatori. Non ho misurato, ma è probabile che lo stesso effetto di "strozzamento" dei puntatori si trovi nei linguaggi dotNET e in altre implementazioni simili.

I linguaggi con puntatori "reali" non avranno questo effetto, switch perderà lì - più grande è la lista delle scelte.

Quindi l'OOP non ha essenzialmente nulla a che fare con questo...

 
MetaDriver:

Vorrei mettere in guardia contro l'eccessiva generalizzazione. Un tale effetto è ragionevole aspettarsi in mql, perché usa "pseudo-puntatori" virtuali - essenzialmente tabelle hash che fanno riferimento alla tabella hash interna (nascosta) degli indirizzi reali. Per risolvere tali puntatori, ci vuole una quantità significativa di tempo extra, ben oltre l'indirizzamento diretto dei puntatori. Non ho misurato, ma è probabile che lo stesso effetto di "strozzamento" dei puntatori si trovi nei linguaggi dotNET e in altre implementazioni simili.

Nelle lingue con puntatori "reali" questo effetto non si verificherà, l'interruttore perderà là fuori - più grande è la lista delle scelte.

Quindi l'OOP non ha essenzialmente nulla a che fare con questo...

È chiaro che è solo il compilatore stesso, quindi con una compilazione "corretta" i tempi di esecuzione degli esempi di cui sopra sarebbero uguali.
 
icas:
È chiaro che è solo una questione del compilatore stesso, quindi se gli esempi di cui sopra sono compilati "correttamente", i tempi di esecuzione saranno uguali.
Il concetto di "correttezza" dipende dalle regole, quindi non ha senso. ;)
 

Faccio subito notare l'errore: le funzioni f sono vuote e completamente tagliate dal compilatore. Cioè, in realtà non c'è nessuna chiamata di funzione. Non sono anche sicuro in quale stato la funzione ff degeneri e se non finirà per essere inline all'interno del ciclo for, eliminando così anche la chiamata alla funzione.

Il metodo virtuale, d'altra parte, non può essere tagliato - è sempre chiamato. Di conseguenza, in un caso il ciclo sta solo girando, e nell'altro caso la chiamata è nel ciclo.

In qualsiasi test, bisogna prima provare la loro correttezza, e solo dopo passare ai risultati.

 

Eccone uno con una funzione non vuota:

File:
test2.mq4  11 kb
 

Ecco tutte le funzioni che sono uniche, inoltre, chiamate via switch, più complesse di un metodo di classe.

File:
test3.mq4  12 kb
 
Integer:

Ecco tutte le funzioni che sono uniche, inoltre, chiamate via switch, più complesse di un metodo di classe.

Che pasticcio...

Avete sentito parlare di inlining? E l'inlining aggressivo?

Cosa succede di solito ai corpi di funzioni semplici e cosa fa un buon compilatore ottimizzatore con loro? Non siamo nel 1995, vero?

 
MetaDriver:

Vorrei mettere in guardia contro l'eccessiva generalizzazione. Un tale effetto è ragionevole aspettarsi in mql, perché utilizza "pseudo-puntatori" virtuali - essenzialmente maniglie che fanno riferimento alla tabella hash interna (nascosta) di indirizzi reali. Per risolvere tali puntatori, ci vuole una quantità significativa di tempo extra, ben oltre l'indirizzamento diretto dei puntatori. Non ho misurato, ma è probabile che lo stesso effetto di "strozzamento" dei puntatori si trovi nei linguaggi dotNET e in altre implementazioni simili.

Nei linguaggi con puntatori "reali" non ci sarà questo effetto, lì l'interruttore perderà - più grande è la lista delle scelte.

Quindi l'OOP non ha essenzialmente nulla a che fare con questo...

Sì, eccolo in Do diesis:)


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

 

Iniziare qualsiasi test dimostrando che è corretto e che misura effettivamente ciò che dice di misurare.

Ciò che è presentato sopra contiene errori incredibili e mostra la completa mancanza di comprensione dell'autore dei meccanismi di compilazione e di come funziona il codice.

 
Renat:

Iniziare qualsiasi test dimostrando che è corretto e che misura effettivamente ciò che dice di misurare.

Ciò che è presentato sopra contiene errori incredibili e mostra la completa mancanza di comprensione dell'autore dei meccanismi di compilazione e di come funziona il codice.

Perché dovrei capire i meccanismi di compilazione? Solo per credere che un cattivo risultato sia meglio di uno buono? È il risultato che conta.