2009-11-15 16 views
7

Ho notato che se stampo una stringa lunga (char *) usando cout sembra stampare 1 carattere alla volta sullo schermo di Windows 7, Vista e Linux (usando stucco) usando Visual C++ 2008 su Windows e G ++ su Linux. Printf è così molto più veloce che ho passato da cout a printf per la maggior parte della stampa in un mio progetto. Questo mi confonde perché questo question sembra che io sia l'unico ad avere questo problema.C++ cout printing lentamente

Ho anche scritto una sostituzione cout che sembra che batte i pantaloni fuori di cout sul mio comp -

class rcout 
{ 
public: 
    char buff[4096]; 
    unsigned int size; 
    unsigned int length; 

    rcout() 
    { 
     size = 4096; 
     length = 0; 
     buff[0] = '\0'; 
    } 

    ~rcout() 
    { 
     printf("%s", buff); 
    } 

    rcout &operator<<(char *b) 
    { 
     strncpy(buff+length, b, size-length); 
     unsigned int i = strlen(b); 
     if(i+length >= size) 
     { 
      buff[size-1] = '\0'; 
      printf("%s", buff); 
      b += (size-length) -1; 
      length = 0; 
      return (*this) << b; 
     } 
     else 
      length += i; 
     return (*this); 
    } 

    rcout &operator<<(int i) 
    { 
     char b[32]; 
     _itoa_s(i, b, 10); 
     return (*this)<<b; 
    } 

    rcout &operator<<(float f) 
    { 
     char b[32]; 
     sprintf_s(b, 32, "%f", f); 
     return (*this)<<b; 
    } 
}; 

int main() 
{ 
    char buff[65536]; 
    memset(buff, 0, 65536); 

    for(int i=0;i<3000;i++) 
     buff[i] = rand()%26 + 'A'; 

    rcout() << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n"; 
    Sleep(1000); 
    cout << "\n\nOk, now cout....\n\n"; 
    cout << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n"; 
    Sleep(1000); 
    cout << "\n\nOk, now me again....\n\n"; 
    rcout() << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n"; 
    Sleep(1000); 

    return 0; 
} 

Tutte le idee perché cout sta stampando così lentamente per me?

+0

Ho provato di nuovo sul computer Linux, e cout e rcout sembravano avere la stessa velocità, ma so che cout era molto più lento di printf nella mia altra app quindi penso che potrebbe essere perché era multithreaded? Poi l'ho provato sul mio comp Vista e ci sono voluti circa 375 ms mentre Rcout ha impiegato circa 100 ms. Su Windows 7 comp cout ci sono voluti 850 ms e Rcout ha impiegato circa 70 ms. –

+0

'<< endl'? 'cout' non scarica automaticamente i dati. È possibile che tu stia eseguendo il buffering dei dati in Windows in modo diverso rispetto a 'printf'.Prova anche 'cerr' invece di' cout' e vedi se fa la differenza: se lo svuota è sicuramente il problema. – quark

+0

cerr ha eseguito la stessa cosa di cout, anche facendo un flush() dopo che il cout non aiuta –

risposta

12

NOTA: questo risultato sperimentale è valido per MSVC. In qualche altra implementazione della libreria, il risultato varierà.

printfpotrebbe essere (molto) più veloce di cout. Sebbene printf analizzi la stringa di formato in runtime, richiede molto meno chiamate di funzione e in realtà richiede un numero ridotto di istruzioni per eseguire lo stesso lavoro, confrontandolo con cout. Ecco una sintesi della mia sperimentazione:

Il numero di istruzioni statica

In generale, cout genera un sacco di codice di printf. Supponiamo di avere il seguente codice cout da stampare con alcuni formati.

os << setw(width) << dec << "0x" << hex << addr << ": " << rtnname << 
    ": " << srccode << "(" << dec << lineno << ")" << endl; 

Su un VC++ compilatore con ottimizzazioni, genera codice intorno byte. Tuttavia, quando lo si sostituisce con il codice basato su printf, sono necessari solo byte.

Il numero di istruzione eseguita dinamicamente

Il numero di istruzioni statica racconta proprio la differenza di codice binario statico. Ciò che è più importante è il numero effettivo di istruzioni che vengono eseguite dinamicamente in runtime. Ho anche fatto una semplice sperimentazione: codice

prova:

int a = 1999; 
char b = 'a'; 
unsigned int c = 4200000000; 
long long int d =98765; 
long long unsigned int e = 123456789; 
float f = 3123.4578f; 
double g = 3.141592654; 

void Test1() 
{ 
    cout 
     << "a:" << a << “\n” 
     << "a:" << setfill('0') << setw(8) << a << “\n” 
     << "b:" << b << “\n” 
     << "c:" << c << “\n” 
     << "d:" << d << “\n” 
     << "e:" << e << “\n” 
     << "f:" << setprecision(6) << f << “\n” 
     << "g:" << setprecision(10) << g << endl; 
} 

void Test2() 
{ 
    fprintf(stdout, 
     "a:%d\n" 
     "a:%08d\n" 
     "b:%c\n" 
     "c:%u\n" 
     "d:%I64d\n" 
     "e:%I64u\n" 
     "f:%.2f\n" 
     "g:%.9lf\n", 
     a, a, b, c, d, e, f, g); 
    fflush(stdout); 
} 

int main() 
{ 
    DWORD A, B; 
    DWORD start = GetTickCount(); 
    for (int i = 0; i < 10000; ++i) 
     Test1(); 
    A = GetTickCount() - start; 

    start = GetTickCount(); 
    for (int i = 0; i < 10000; ++i) 
     Test2(); 
    B = GetTickCount() - start; 

    cerr << A << endl; 
    cerr << B << endl; 
    return 0; 
} 

Ecco il risultato di Test1 (cout):

  • di istruzione eseguita: 423.234.439

  • della memoria carichi/negozi: ca. 320.000 e 980.000

  • tempo trascorso: 52 secondi

Poi, che dire printf? Questo è il risultato di Test2:

  • di istruzione eseguita: 164.800.800

  • dei carichi di memoria/negozi: ca. 70.000 e 180.000

  • Tempo impiegato: 13 secondi

In questa macchina e compilatore, printf era molto più veloce cout. In entrambe le istruzioni eseguite e # di caricamento/memorizzazione (indica # di mancate cache) hanno 3 ~ 4 volte le differenze.

So che questo è un caso estremo.Inoltre, devo notare che cout è molto più semplice quando si gestiscono dati a 32/64 bit e si richiede l'indipendenza dalla piattaforma 32/64. C'è sempre un compromesso. Sto usando cout quando il controllo del tipo è molto complicato.

Okay, cout in MSVS fa schifo solo :)

+0

Questo non è corretto; 'cout' non è sempre più veloce di' printf' con qualsiasi mezzo. Vedi il mio post per i dettagli. –

+0

Ho corretto la mia risposta. Ma i miei esperimenti su Windows/Linux danno sempre coerenza. 'cout' è più lento di' printf'. Ho anche contato # di istruzioni eseguite. Sì, 'cout' aveva bisogno di più di' printf'. In Linux, il 20% di istruzioni in più erano necessarie per 'cout'. – minjang

+4

risposta scelta per "Ok, cout in MSVS fa schifo :)", hai ragione, questo è il problema –

8

Suggerirei di provare questo stesso test su un altro computer. Non ho una buona risposta per spiegare perché questo potrebbe accadere; tutto quello che posso dire è che non ho mai notato una differenza di velocità tra cout e printf. Ho anche testato il tuo codice usando gcc 4.3.2 su Linux e non c'era alcuna differenza.

Detto questo, non è possibile sostituire facilmente cout con la propria implementazione. Il fatto è che cout è un'istanza di std :: ostream che ha un lotto di funzionalità incorporato che è necessario per l'interoperabilità con altre classi che sovraccaricano gli operatori iostream.

Edit:

Qualcuno che dice printf è sempre più veloce di std::cout è semplicemente sbagliato. Ho appena eseguito il codice di test pubblicato da minjang, con gcc 4.3.2 e il flag -O2 su un AMD Athlon X2 a 64 bit, e cout era in realtà più veloce.

ho ottenuto i seguenti risultati:

printf: 00:00:12.024 
cout: 00:00:04.144 

E` cout sempre più veloce di printf? Probabilmente no. Soprattutto non con implementazioni precedenti. Ma su implementazioni più recenti gli iostream sono probabilmente più veloci di stdio perché invece di analizzare una stringa di formato in fase di esecuzione, il compilatore sa al momento della compilazione quali funzioni deve chiamare per convertire interi/float/oggetti in stringhe.

Ma, cosa più importante, la velocità di printf rispetto a cout dipende dall'implementazione e quindi il problema descritto dall'OP non è facilmente spiegabile.

+1

Ho anche provato su Linux con icc -O3 su Xeon. Misurato da 'time' e metti'>/dev/null'. In ogni caso, 'cout' richiede più istruzioni da completare. Ma le differenze sono piccole. Ad esempio, cout 0.311 vs printf 0.218. Ma sono assolutamente d'accordo che dipende dall'implementazione. Ho modificato la mia risposta. – minjang

+0

@minjang Penso che il test potrebbe essere più significativo se non si invia lo stdout a dev/null –

+0

@Ramonster, printf ancora più veloce. Alcuni dettagli: compilato da g ++ w/-O3. cout ha impiegato 4.9 secondi, ma printf ha impiegato 4,5 secondi. Non una grande differenza però. Ma, # di istruzioni eseguite sono 775M per cout, 589M per printf. In realtà, le differenze di 200 milioni nelle moderne CPU sono piuttosto piccole. Inoltre, ho bisogno di presumere che ogni istruzione richiederebbe un tempo simile (so che non è così ragionevole). Comunque, nella mia sperimentazione, printf è stato più veloce su Linux e Windows. – minjang

0

Provare a utilizzare alcuni endl s o flush es in quanto saranno svuotare tampone cout s', nel caso in cui il sistema operativo è la cache di output del vostro programma per qualsiasi ragione. Ma, come dice Charles, non c'è una buona spiegazione per questo comportamento, quindi se questo non aiuta, è probabile che si tratti di un problema specifico della tua macchina.

+0

Ho provato ad usare endl e flush(), non sembrano fare la differenza. Ho cronometrato la stampa e ottenuto 842 ms per cout e 63 ms per il mio rcout –

1

Sulla base della mia esperienza nella programmazione delle competizioni, printf è più veloce di cout.

Mi ricordo molte volte in cui la mia soluzione non ce l'ha fatta prima del tempo limite solo a causa di cin/cout, mentre printf/scanf ha funzionato.

Inoltre, sembra normale (almeno per me) che cout sia più lento di printf, perché fa più operazioni.

+0

Non dovrebbe mai * essere * molto più lento, nella misura descritta dall'OP. –

-2

Ecco hax che dovrebbe rendere C++ flusso veloce come c printf. Non l'ho mai provato ma credo che funzioni.

ios_base::sync_with_stdio(0); 
+0

Non l'ho mai provato? – Tim

4

Prova chiamare ios::sync_with_stdio(false); prima di usare std :: cout/cin, a meno che naturalmente, si mescolano stdio e iostream nel vostro programma, che è una brutta cosa da fare.

+0

che non sembra fare la differenza –

+0

Sei sicuro di utilizzare la build "versione/ottimizzata"? iostream tende ad essere molto più lento in modalità di debug a causa del codice del template. – obecalp

0

È consigliabile provare prima a scrivere tutti i dati su ostringstream e quindi utilizzare su ostringstreamstr(). Sono su 64-bit Windows 7 e Test1 era già significativamente più veloce di Test2 (il tuo chilometraggio può variare). Utilizzando un ostringstream per creare prima una singola stringa e quindi utilizzando , diminuire ulteriormente il tempo di esecuzioneTest1 di un fattore compreso tra 3 e 4. Assicurarsi di #include <sstream>.

cioè sostituire

void Test1() 
{ 
    cout 
     << "a:" << a << "\n" 
     << "a:" << setfill('0') << setw(8) << a << "\n" 
     << "b:" << b << "\n" 
     << "c:" << c << "\n" 
     << "d:" << d << "\n" 
     << "e:" << e << "\n" 
     << "f:" << setprecision(6) << f << "\n" 
     << "g:" << setprecision(10) << g << endl; 
} 

con:

void Test1() 
{ 
    ostringstream oss; 
    oss 
     << "a:" << a << "\n" 
     << "a:" << setfill('0') << setw(8) << a << "\n" 
     << "b:" << b << "\n" 
     << "c:" << c << "\n" 
     << "d:" << d << "\n" 
     << "e:" << e << "\n" 
     << "f:" << setprecision(6) << f << "\n" 
     << "g:" << setprecision(10) << g << endl; 
    cout << oss.str(); 
} 

Ho il sospetto ostringstream rende questo modo molto più veloce a causa di non cercando di scrivere sullo schermo ogni volta che si chiama operator<< su cout. Ho anche notato attraverso l'esperienza che la riduzione del numero di volte che si scrive sullo schermo (scrivendo di più contemporaneamente) aumenta le prestazioni (anche in questo caso, il tuo chilometraggio può variare).

esempio

void Foo1() 
{ 
    for(int i = 0; i < 10000; ++i) { 
     cout << "Foo1\n"; 
    } 
} 

void Foo2() 
{ 
    std::string s; 
    for(int i = 0; i < 10000; ++i) { 
     s += "Foo2\n"; 
    } 
    cout << s; 
} 

void Foo3() 
{ 
    std::ostringstream oss; 
    for(int i = 0; i < 10000; ++i) { 
     oss << "Foo3\n"; 
    } 
    cout << oss.str(); 
} 

Nel mio caso, ha preso Foo1 1,092ms, Foo2 presero 234ms e 218ms Foo3 prese. ostingstream s sono tuoi amici. Ovviamente Foo2 e Foo3 richiedono (banalmente) più memoria. Per confrontare questo aspetto con una funzione in stile C, provare sprintf in un buffer e quindi scrivere quel buffer utilizzando fprintf e si dovrebbe vedere ancora più efficienza su Test2 (anche se per me questa prestazione è stata migliorata di Test2 di circa il 10% circa; cout e printf sono davvero bestie sotto il cofano).

Compilatore: MinGW64 (TDM e le relative librerie raggruppate).

0

Provare a utilizzare ios::sync_with_stdio(false);. Menzionalo prima di usare std :: cin/cout. Non mischia stdio o iostream ma sincronizza i flussi standard iostream con i corrispondenti flussi c standard. per esempio - std :: cin/wcin di iostream è sincronizzato con stdin di c stream