52 votes

mélanger cout et printf pour une sortie plus rapide

Après avoir effectué quelques tests, j'ai remarqué qu' printf est beaucoup plus rapide que cout. Je sais qu'il est dépendant de l'implémentation, mais sur ma machine sous Linux, printf est 8x plus rapide. Donc, mon idée est de mélanger les deux méthodes d'impression: je veux utiliser cout pour les tirages, et j'ai l'intention d'utiliser printf pour la production d'énormes sorties (généralement dans une boucle). Je pense qu'il est sécuritaire de le faire aussi longtemps que je n'oublie pas de rincer avant de passer à l'autre méthode:

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

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

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

C'est OK comme ça?

Mise à jour: Merci pour tous les précieux retours. Résumé des réponses: si vous voulez éviter la délicate des solutions, il suffit simplement de ne pas utiliser endl avec cout depuis il vide le tampon implicitement. Utiliser "\n" à la place. Il peut être intéressant si vous produire de grands résultats.

79voto

Jerry Coffin Points 237758

La réponse directe est que, oui, c'est correct.

Beaucoup de gens ont jeté autour de différentes idées pour améliorer la vitesse, mais il semble être tout à fait un peu de désaccord sur ce qui est le plus efficace. J'ai décidé d'écrire un petit programme de test pour obtenir au moins une idée de quelles sont les techniques qui a fait quoi.

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

static const int count = 3000000;
static char const *const string = "This is a string.";

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("%s\n", 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);
}

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");
    return 0;
}

J'ai couru ce sur Windows après compilation avec VC++ 2008 (les versions x86 et x64). La sortie d'un run (avec sortie redirigée vers un fichier de disque) ressemblait à ceci:

             Time using printf: 1.975
               Time using puts: 1.458
      Time using cout (synced): 1.297
   Time using cout (un-synced): 1.28
       Time using stringstream: 2.03
               Time using endl: 12.621
             Time using fill_n: 1.285

Comme prévu, les résultats varient, mais il ya quelques points que j'ai trouvé intéressant:

  1. printf/met sont beaucoup plus rapides que le cout lors de l'écriture sur le NUL de l'appareil
  2. ...mais le cout tient très bien lors de l'écriture dans un fichier réel
  3. Tout à fait quelques optimisations proposées accomplir peu
    1. Dans mes tests, fill_n est à peu près aussi rapide que toute autre chose
De loin le plus gros de l'optimisation est d'éviter endl

22voto

William Bell Points 367

L'envoi de std::endl au flux ajoute un newline et purge le flux. L'invocation ultérieure de cout.flush() est superflue. Si cela était fait en synchronisant cout vs printf alors vous ne compariez pas des pommes avec des pommes.

12voto

Loki Astari Points 116129

Notez également que le C++ flux de données est synchronisée sur le C flux.
Par conséquent, il ne travail supplémentaire pour rester en synchronisation.

Une autre chose à noter est à assurez-vous de vider le flux d'une quantité égale. Si vous continiously vider le flux sur un système et pas l'autre, ce qui va certainement affecter la vitesse de tests.

Avant de supposer que l'un est plus rapide que les autres, vous devriez:

  • onu-sync C++ I/O C I/O (voir sync_with_stdio() ).
  • Assurez-vous que le montant de bouffées de chaleur est comparable.

10voto

wallyk Points 33150

Vous pouvez améliorer encore les performances de printf en augmentant la taille de la mémoire tampon pour 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
 

Le nombre d'appels au système d'exploitation pour effectuer des E / S est presque toujours le composant et le limiteur de performances les plus coûteux.

Bien sûr, si cout sortie est mélangé à stdout , les vidages de mémoire tampon annulent l’objectif d’une taille de mémoire tampon accrue.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X