Domanda

Dopo aver eseguito alcuni test ho notato che printf è molto più veloce di cout. So che è dipendente di attuazione, ma sulla mia macchina printf Linux è 8x più veloce. Quindi la mia idea è quella di mescolare i due metodi di stampa: voglio usare cout per stampe semplici, e ho intenzione di utilizzare per la produzione di printf uscite enormi (in genere in un loop). Penso che sia sicuro di fare finché non dimentico di lavare prima di passare alla altro metodo:

cout << "Hello" << endl;
cout.flush();

for (int i=0; i<1000000; ++i) {
    printf("World!\n");
}
fflush(stdout);

cout << "last line" << endl;
cout << flush;

E 'OK del genere?

Aggiornamento: Grazie per tutti i preziosi feedback. Sintesi delle risposte: se si vuole evitare soluzioni difficili, semplicemente non utilizzare endl con cout dal momento che svuota il buffer in modo implicito. Utilizzare "\n" invece. Può essere interessante se si produce di grandi dimensioni uscite.

È stato utile?

Soluzione

La risposta diretta è che sì, va bene.

Un sacco di persone hanno gettati in giro varie idee su come migliorare la velocità, ma sembra che ci sia un po 'di disaccordo che è più efficace. Ho deciso di scrivere un programma di test rapido per ottenere almeno qualche idea di quali tecniche hanno fatto quello.

#include <iostream>
#include <string>
#include <sstream>
#include <time.h>
#include <iomanip>
#include <algorithm>
#include <iterator>
#include <stdio.h>

char fmt[] = "%s\n";
static const int count = 3000000;
static char const *const string = "This is a string.";
static std::string s = std::string(string) + "\n";

void show_time(void (*f)(), char const *caption) { 
    clock_t start = clock();
    f();
    clock_t ticks = clock()-start;
    std::cerr << std::setw(30) << caption 
        << ": " 
        << (double)ticks/CLOCKS_PER_SEC << "\n";
}

void use_printf() {
    for (int i=0; i<count; i++)
        printf(fmt, string);
}

void use_puts() {
    for (int i=0; i<count; i++) 
        puts(string);        
}

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

void use_cout_unsync() { 
    std::cout.sync_with_stdio(false);
    for (int i=0; i<count; i++)
        std::cout << string << "\n";
    std::cout.sync_with_stdio(true);
}

void use_stringstream() { 
    std::stringstream temp;
    for (int i=0; i<count; i++)
        temp << string << "\n";
    std::cout << temp.str();
}

void use_endl() { 
    for (int i=0; i<count; i++)
        std::cout << string << std::endl;
}

void use_fill_n() { 
    std::fill_n(std::ostream_iterator<char const *>(std::cout, "\n"), count, string);
}

void use_write() {
    for (int i = 0; i < count; i++)
        std::cout.write(s.data(), s.size());
}

int main() { 
    show_time(use_printf, "Time using printf");
    show_time(use_puts, "Time using puts");
    show_time(use_cout, "Time using cout (synced)");
    show_time(use_cout_unsync, "Time using cout (un-synced)");
    show_time(use_stringstream, "Time using stringstream");
    show_time(use_endl, "Time using endl");
    show_time(use_fill_n, "Time using fill_n");
    show_time(use_write, "Time using write");
    return 0;
}

Ho eseguito questo su Windows dopo la compilazione con VC ++ 2013 (entrambe le versioni x86 e x64). Uscita da una corsa (con uscita reindirizzato a un file su disco) si presentava così:

          Time using printf: 0.953
            Time using puts: 0.567
   Time using cout (synced): 0.736
Time using cout (un-synced): 0.714
    Time using stringstream: 0.725
            Time using endl: 20.097
          Time using fill_n: 0.749
           Time using write: 0.499

Come previsto, i risultati variano, ma ci sono alcuni punti che ho trovato interessante:

  1. printf / puts sono molto più veloce di cout quando si scrive alla periferica NUL
    • ma cout mantiene abbastanza bene quando si scrive in un file vero e proprio
  2. Un bel paio di ottimizzazioni proposte compire poco
    • Nel mio test, fill_n è circa veloce come qualsiasi altra cosa
  3. Di gran lunga il più grande di ottimizzazione è di evitare endl
  4. cout.write ha dato il tempo più veloce (anche se probabilmente non con un margine significativo

Recentemente ho modificato il codice per forzare una chiamata a printf. Anders Kaseorg era gentile da sottolineare - che g++ riconosce la specifica sequenza printf("%s\n", foo); equivale a puts(foo);, e genera codice di conseguenza (cioè, genera il codice da chiamare puts anziché printf). Spostando la stringa di formato a una matrice globale, e passando che la stringa di formato produce output identico, ma obbliga a essere prodotta mediante printf anziché puts. Naturalmente, è possibile che potrebbero ottimizzare intorno a questo un giorno pure, ma almeno per ora (g ++ 5.1) un test con g++ -O3 -S conferma che in realtà è chiamando printf (dove il codice precedente compilato per una chiamata a puts).

Altri suggerimenti

L'invio std::endl al flusso aggiunge un newline e vampate il torrente. La successiva invocazione di cout.flush() è superflua. Se questo è stato fatto quando temporizzazione cout vs. printf allora non stavate confrontando le mele alle mele.

Per default, flussi d'uscita standard del C ++ e C sono sincronizzati, in modo che crei una provoca un colore degli altri, vampate così espliciti non sono necessari.

Si noti inoltre che il C ++ flusso è sincronizzato al flusso C.
Così fa lavoro extra per rimanere in sincronia.

Un'altra cosa da notare è quello di assicurarsi di lavare i flussi di pari importo. Se si svuota continuamente il flusso su un sistema e non l'altro che sarà sicuramente influire sulla velocità dei test.

Prima di assumere che uno è più veloce rispetto agli altri è necessario:

  • non-sync C ++ I / O da C di I / O (vedi sync_with_stdio ()).
  • Assicurarsi che la quantità di vampate è paragonabile.

È possibile migliorare ulteriormente le prestazioni del printf aumentando la dimensione del buffer per stdout:

setvbuf (stdout, NULL, _IOFBF, 32768);  // any value larger than 512 and also a
                  // a multiple of the system i/o buffer size is an improvement

Il numero di chiamate al sistema operativo per eseguire I / O è quasi sempre il componente e le prestazioni più costoso limitatore.

Naturalmente, se l'uscita è cout mescolati con stdout, le vampate tampone eliminare la caratteristica di un aumento delle dimensioni del buffer.

È possibile utilizzare sync_with_stdio per rendere C ++ IO più veloce.

cout.sync_with_stdio(false);

Dovrebbe migliorare la perfomance di uscita con cout.

Non preoccuparti per le prestazioni tra il printf e cout. Se si desidera ottenere le prestazioni, un output formattato indipendenti dall'uscita non formattato.

puts("Hello World\n") è molto più veloce di printf("%s", "Hellow World\n"). (principalmente a causa del sovraccarico di formattazione) Una volta isolato il formattato dal testo semplice, si può fare trucchi come:.

const char hello[] = "Hello World\n";
cout.write(hello, sizeof(hello) - sizeof('\0'));

Per accelerare output formattato, il trucco è eseguire la formattazione di una stringa, quindi utilizzare uscita del blocco con la stringa (o buffer):

const unsigned int MAX_BUFFER_SIZE = 256;
char buffer[MAX_BUFFER_SIZE];
sprintf(buffer, "%d times is a charm.\n", 5);
unsigned int text_length = strlen(buffer) - sizeof('\0');
fwrite(buffer, 1, text_length, stdout);

Per migliorare ulteriormente le prestazioni del tuo programma, ridurre la quantità di output. La roba meno te l'uscita, più velocemente il vostro programma sarà. Un effetto collaterale sarà che la dimensione del file eseguibile si ridurrà anche.

Beh, non posso pensare di qualsiasi ragione di utilizzare effettivamente cout ad essere onesti. E 'completamente folle ad avere un enorme modello ingombrante per fare qualcosa di così semplice che sarà in ogni file. Inoltre, è come se fosse stato progettato per essere il più lento a scrivere il più possibile e dopo la milionesima volta di battitura <<<< e digitando il valore in mezzo e ottenere qualcosa di Lik> nomeVariabile >>> su incidente non ho mai voglia di farlo di nuovo .

Per non parlare se si include namespace std il mondo finirà per implodere, e non se fate il vostro fardello digitazione diventa ancora più ridicolo.

Comunque non mi piace printf molto neanche. Per me, la soluzione è quella di creare la mia classe concreta e quindi chiamare qualunque cosa io roba è necessaria all'interno di quella. Poi si può avere molto semplice io in qualsiasi modo si desidera e con qualsiasi applicazione che si desidera, qualsiasi formattazione che si desidera, ecc (in genere si vuole carri per essere sempre un modo, per esempio, di non formattare le 800 modi per nessun motivo, in modo da mettere nella formattazione con ogni chiamata è uno scherzo).

Quindi tutto quello che digito è qualcosa di simile dout + "Questo è più sano di "+ cPlusPlusMethod +" di "+ debugIoType +" IMO, almeno."; dout ++;

, ma si può avere tutto quello che vuoi. Con un sacco di file che è sorprendente quanto questo migliora la compilazione tempo, troppo.

Inoltre, non c'è niente di sbagliato con la miscelazione C e C ++, si deve solo essere fatto jusdiciously e se si utilizzano le cose che causano i problemi con l'utilizzo di C, in primo luogo è sicuro di dire l'ultima delle vostre preoccupazioni sono problemi da mescolando C e C ++.

miscelazione C ++ e C iomethods è stato raccomandato contro dai miei libri C ++, FYI. Sono abbastanza sicuro che le funzioni C calpestano stato previsto / tenuto da C ++.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top