2010-08-02 8 views
5

ho le seguenti due cicli:Domanda sul ciclo di velocità

#include <iostream> 
#include <stdlib.h> 
#include <time.h> 

using namespace std; 
int main(){ 

    int start=clock(); 
    for (int i=0;i<100;i++) 
     cout<<i<<" "<<endl; 
    cout<<clock()-start<<"\n"<<endl; 
    cout<<"\n"; 

    int start1=clock(); 
    for (int j=0;j<100;++j) 
     cout<<j<<" "<<endl; 
    cout<<"\n"; 
    cout<<clock()-start1<<" \n "<<endl; 

    return 0; 
} 

ho incontrato che per tre volte. Nelle prime due corse, il secondo giro era più veloce ma, alla terza, il primo giro era il più veloce. Cosa significa questo? Che è migliore? Dipende dalla situazione?

+4

100 iterazioni possono essere troppo piccole per trarre conclusioni ... – Vladimir

+0

Un altro modo per verificare come il tuo il codice sta facendo nell'area delle prestazioni è guardare l'assemblaggio generato. Probabilmente vedrai la * stessa * stessa cosa generata per ogni ciclo. L'incremento pre-versus post per i tipi primitivi è lo stesso. – GManNickG

+0

@GMan: come può essere lo stesso se la semantica è diversa? D'accordo: l'ottimizzatore probabilmente individuerà il valore di ritorno del postfix da non utilizzare e generando così lo stesso smontaggio. – xtofl

risposta

5

Nel tuo caso è probabilmente l'errore di misura standard e non importa cosa si usa il post o preincremento . Per i tipi standard (int, byte ...) non importa.

MA ci si dovrebbe abituare all'uso del pre-incremento perché ci sono implicazioni di prestazioni se le si utilizza in una Classe, a seconda di come sono implementati tali operatori. operatore di post-incremento i ++ deve fare una copia dell'oggetto

Ad esempio:

class integer 
{ 
public: 
    integer(int t_value) 
    : m_value(t_value) 
    { 
    } 

    int get_value() { return m_value; } 

    integer &operator++() // pre increment operator 
    { 
    ++m_value; 
    return *this; 
    } 

    integer operator++(int) // post increment operator 
    { 
    integer old = *this; // a copy is made, it's cheap, but it's still a copy 
    ++m_value; 
    return old; // Return old copy 
    } 

private: 
    int m_value; 

Date un'occhiata al seguente risposta

StackOverflow: i++ less efficient than ++i, how to show this?

+1

Non solo l'efficienza è influenzata, ma in realtà significa qualcosa di diverso. – xtofl

+0

@xtofl: come mai? (La discussione riguarda l'incremento pre/post come espressione separata). – UncleBens

1

Significa che dovresti usare tecniche statistiche per capire quale ciclo è più veloce (e spero che queste tecniche dimostrino che erano praticamente alla pari).

Hai no idea che cosa sta facendo la tua CPU al di sopra del carico che stai mettendo qui sotto.

Potrebbe essere l'avvio di attività pianificate, la gestione degli interrupt, tutti i tipi di cose che potrebbero distorcere i risultati.

Potrebbe essere necessario eseguire un milione di esecuzioni, eliminare i valori anomali e calcolare il resto medio per ottenere un campione decente.

In cima a quello, un centinaio di iterazioni non è molto, soprattutto perché si sta facendo chiamate di funzione a cout che può ben palude il tempo trascorso a fare il controllo ad anello.

Quando si eseguono i controlli in UNIX, I non utilizzare il tempo trascorso per questo motivo. Il sistema e l'ora dell'utente indicano quanti secondi la CPU era in uso per il processo specificato, indipendentemente dal tempo trascorso.

1

++ dovrei produrre lo stesso codice macchina di i ++ con risultato inutilizzato su qualsiasi compilatore a metà strada (a condizione che non sia sovraccaricato in modo elegante, il che non può essere il caso di int). E anche se non fosse così (avresti bisogno di scovare un compilatore piuttosto stupido del secolo scorso), la differenza è così piccola che non dovresti mai dovertene preoccupare. Bene, ci sono casi in cui è necessario spremere fuori ogni piccola parte di prestazioni, ma almeno tutti noi entriamo in questa situazione. E anche in questo caso, il corpo del loop ha molto più potenziale di ottimizzazione (anche nel tuo esempio semplicistico: l'I/O è molto più costoso rispetto alla copia di una parola macchina).

Oppure in una frase: l'ottimizzazione prematura è la radice di tutto il male.

4

Questi loop sono equivalenti per la variabile di induzione di tipo int. Qui è stata data risposta più volte alle domande di incremento post-pre-incremento. Prova a cercare un po 'negli archivi.

Inoltre, l'operazione di incremento richiede solo una piccola frazione di tempo rispetto all'IO standard. Il tuo test sta misurando la velocità dell'IO piuttosto che la velocità delle operazioni di incremento.

10

Il tempo di esecuzione dei loop è dominato in modo preponderante dalle operazioni di input-output. Ciò significa che il tempo di osservazione 1) non ha nulla a che fare con le prestazioni effettive del loop (ad esempio i++ vs ++j), 2) è praticamente imprevedibile e instabile (in sostanza casuale).

In altre parole, il tuo esperimento non ha senso. Significa assolutamente nulla.

Infine, in situazioni in cui non viene utilizzato il risultato dell'operatore ++ integrato, non vi è assolutamente alcuna differenza tra incremento postfisso e prefisso. In qualsiasi compilatore ragionevole entrambi i tuoi loop avranno prestazioni assolutamente identiche.

+2

Scommetto che se compila questo in linguaggio assembly, i due loops saranno esattamente uguali – Jaka

-1

++ i è preincremento
i ++ è il post-

vedere Operator per i dettagli

+0

Penso che lo sappia. – GManNickG

+0

Risposta semplice. Astuto. Se avessi aggiunto qualcosa su cosa significasse lo _premi_ di incremento pre- e post, avrei + 1 tu. – xtofl

1

Da quello che vedo, l'unica la differenza nei loop è l'incremento pre/post della variabile loop. La maggior parte del tempo di processo sarà speso per il cout. L'incremento sarà di tempo trascurabile in confronto.

3

Vecchio GCC 3.4.4 fa questo:

Primo ciclo:

.L11: 
     cmpl $99, -8(%ebp) 
     jg  .L12 
     subl $8, %esp 
     pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 
     subl $12, %esp 
     pushl $.LC0 
     subl $12, %esp 
     pushl -8(%ebp) 
     pushl $_ZSt4cout 
.LCFI7: 
     call _ZNSolsEi 
     addl $20, %esp 
     pushl %eax 
     call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 
     addl $20, %esp 
     pushl %eax 
.LCFI8: 
     call _ZNSolsEPFRSoS_E 
     addl $16, %esp 
     leal -8(%ebp), %eax 
     incl (%eax) 
     jmp  .L11 
.L12: 

Secondo ciclo:

.L14: 
     cmpl $99, -12(%ebp) 
     jg  .L15 
     subl $8, %esp 
     pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 
     subl $12, %esp 
     pushl $.LC0 
     subl $12, %esp 
     pushl -12(%ebp) 
     pushl $_ZSt4cout 
.LCFI13: 
     call _ZNSolsEi 
     addl $20, %esp 
     pushl %eax 
     call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 
     addl $20, %esp 
     pushl %eax 
.LCFI14: 
     call _ZNSolsEPFRSoS_E 
     addl $16, %esp 
     leal -12(%ebp), %eax 
     incl (%eax) 
     jmp  .L14 
.L15: 

Riesci a trovare le differenze? :) (inoltre io e j siamo in posizioni diverse sullo stack -8 (% ebp) e -12 (% ebp))