Domanda

Ho notato che se stampo una stringa lunga (char*) utilizzando cout sembra che venga stampato 1 carattere alla volta sullo schermo in Windows 7, Vista e Linux (utilizzando putty) utilizzando Visual C++ 2008 su Windows e G++ su Linux.Printf è molto più veloce che in realtà sono passato da cout a printf per la maggior parte delle stampe in un mio progetto.Questo mi confonde perché questo domanda mi sembra che io sia l'unico ad avere questo problema.

Ho anche scritto un sostituto di cout che sembra battere i pantaloni di cout sul mio computer -

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;
}

Qualche idea sul perché cout sta stampando così lentamente per me?

È stato utile?

Soluzione

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

printf Potevo essere (molto) più veloce di cout.Sebbene printf analizza la stringa di formato in runtime, richiede molte meno chiamate di funzione e in realtà necessita di un numero ridotto di istruzioni per eseguire lo stesso lavoro, rispetto a cout.Ecco un riassunto della mia sperimentazione:

Il numero di istruzioni statiche

Generalmente, cout genera molto codice rispetto a printf.Diciamo che abbiamo quanto segue cout codice da stampare con alcuni formati.

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

Su un compilatore VC++ con ottimizzazioni, genera around 188 codice byte.Ma quando lo sostituisci printfsolo codice basato su 42 i byte sono obbligatori.

Il numero di istruzioni eseguite dinamicamente

Il numero di istruzioni statiche indica solo la differenza del codice binario statico.Ciò che è più importante è il numero effettivo di istruzioni eseguite dinamicamente in runtime.Ho fatto anche una semplice sperimentazione:

Codice di prova:

int a = 1999;
char b = 'a';
unsigned int c = 4200000000;
long long int d = 987654321098765;
long long unsigned int e = 1234567890123456789;
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 del Test1 (cout):

  • di istruzione eseguita:423.234.439

  • di carichi/immagazzinamenti di memoria:ca.320.000 e 980.000

  • Tempo trascorso: 52 secondi

Allora, che dire? printf?Questo è il risultato del Test2:

  • di istruzione eseguita:164.800.800

  • di carichi/immagazzinamenti di memoria:ca.70.000 e 180.000

  • Tempo trascorso: 13 secondi

In questa macchina e compilatore, printf era molto più veloce cout.In entrambi i casi il numero di istruzioni eseguite e il numero di caricamenti/memorizza (indica il numero di errori di cache) presentano differenze di 3~4 volte.

So che questo è un caso estremo.Inoltre, dovrei tenerlo presente 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 controllare il tipo è molto complicato.

Va bene, cout in MSVS fa semplicemente schifo :)

Altri suggerimenti

Vorrei suggerire di provare questo stesso test su un computer diverso. Non ho una buona risposta per il motivo per cui questo potrebbe accadere; tutto quello che posso dire è che non ho mai notato una differenza di velocità tra cout e printf. Ho anche provato il codice utilizzando gcc 4.3.2 su Linux e non c'era alcuna differenza.

Detto questo, non si può sostituire facilmente cout con una propria implementazione. Il fatto è, cout è un'istanza di std :: ostream che ha molto di funzionalità incorporata in esso che è necessario per l'interoperabilità con le altre classi che sovraccaricano gli operatori iostream.

Modifica

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

ho ottenuto i seguenti risultati:

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

È cout sempre più veloce di printf? Probabilmente no. Soprattutto non con le implementazioni più anziani. Ma su implementazioni più recenti iostreams sono suscettibili di essere più veloce di stdio perché invece di parsing una stringa di formato in fase di esecuzione, il compilatore conosce al momento della compilazione le funzioni che ha bisogno di chiamare per convertire interi / carri / oggetti in stringhe.

Ma ancora più importante, la velocità di printf contro cout dipende dall'implementazione , e quindi il problema descritto dal PO non è facilmente spiegabile.

Prova chiamata 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.

In base alla mia esperienza nelle competizioni di programmazione, 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.

Oltre a questo, sembra normale (almeno per me) che cout è più lento di printf, perché fa più operazioni.

Prova a usare un po 'di endl s o flush ES in quanto saranno flush del buffer di cout, nel caso in cui il sistema operativo è la cache di output del vostro programma per qualsiasi ragione . Ma, come dice Charles, non c'è nessuna buona spiegazione per questo comportamento, quindi se questo non aiuta, allora è probabile un problema specifico alla vostra macchina.

Si dovrebbe cercare di scrivere tutti i dati in un ostringstream prima, e quindi utilizzare cout sul ostringstream del str(). Io sono a 64-bit di Windows 7 e Test1 era già significativamente più veloce di Test2 (la tua situazione potrebbe essere diversa). L'utilizzo di un ostringstream per costruire una singola stringa prima e poi usando cout su quel ulteriormente diminuito di Test1 tempo di esecuzione di un fattore di circa 3 a 4. Assicurarsi di #include <sstream>.

vale a dire., 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 in 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 alla schermata (scrivendo più in una sola volta) aumenta le prestazioni (ancora una volta, la vostra situazione potrebbe essere diversa).

per es.,

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 prese 234ms e 218ms Foo3 prese. ostingstreams sono tuo amico. Ovviamente foo2 e Foo3 richiedono (banalmente) più memoria. Per confrontare questo contro una funzione C-stile, provare sprintf in un buffer e poi scrivere che buffer utilizzando fprintf e si dovrebbe vedere ancora più efficienza nel Test2 (anche se per me questo solo miglioramento delle prestazioni di Test2 di circa il 10% o giù di lì; cout e printf sono infatti diversi animali sotto il cofano).

Compiler:. MinGW64 (TDM e le sue librerie in bundle)

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

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

ios_base::sync_with_stdio(0);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top