Performance d’entrée C ++

J’essayais de résoudre un problème sur InterviewStreet. Après un certain temps, j’ai déterminé que je passais la majeure partie de mon temps à lire les données. Cette question particulière a suscité beaucoup de commentaires, ce qui est donc logique. Ce qui n’a aucun sens, c’est pourquoi les différentes méthodes d’entrée ont eu des performances si différentes:

Au début j’avais:

std::ssortingng command; std::cin >> command; 

Le remplacer le rendit sensiblement plus rapide:

 char command[5]; cin.ignore(); cin.read(command, 5); 

Réécrire tout pour utiliser scanf l’a rendu encore plus rapide

 char command; scanf("get_%c", &command); 

Tout compte fait, j’ai réduit le temps de lecture de l’entrée d’environ 1/3.

Je me demande s’il y a une telle variation de performance entre ces différentes méthodes. De plus, je me demande pourquoi l’utilisation de gprof n’a pas mis en évidence le temps que je passais dans les E / S, mais a plutôt semblé blâmer mon algorithme.

Il existe une grande variation dans ces routines car la vitesse d’entrée de la console n’a presque jamais d’importance.

Et là où il (shell Unix), le code est écrit en C, lit directement à partir du périphérique stdin et est efficace.

Au risque d’être abaissés, les stream d’E / S sont, en général, plus lents et plus volumineux que leurs homologues C. Ce n’est pas une raison pour éviter de les utiliser bien que dans de nombreux cas, car ils sont plus sûrs (jamais rencontré un bogue scanf ou printf? Pas très agréable) et plus généraux (ex: opérateur d’insertion surchargé vous permettant de générer des types définis par l’utilisateur). Mais je dirais aussi que ce n’est pas une raison pour les utiliser de manière dogmatique dans un code très critique en termes de performances.

Je trouve cependant les résultats un peu surprenants. Sur les trois que vous avez énumérés, je l’aurais soupçonné d’être le plus rapide:

 char command[5]; cin.ignore(); cin.read(command, 5); 

Raison: aucune allocation de mémoire n’est nécessaire et lecture directe d’un tampon de caractères. Ceci est également vrai pour votre exemple C ci-dessous, mais appeler scanf pour lire un seul caractère à plusieurs resockets n’est pas non plus optimal, même au niveau conceptuel, car scanf doit parsingr la chaîne de format que vous avez transmise à chaque fois. Je serais intéressé par les détails de votre code d’E / S, car il semble qu’il y ait une possibilité raisonnable que quelque chose ne se passe pas bien lorsque les appels de scanf pour lire un seul caractère s’avèrent être les plus rapides. Je dois juste demander et sans vouloir offenser, mais le code est-il vraiment compilé et associé à des optimisations?

Passons maintenant à votre premier exemple:

 std::ssortingng command; std::cin >> command; 

Nous pouvons nous attendre à ce que cela soit un peu plus lent que optimal, du fait que vous travaillez avec un conteneur de taille variable (std :: ssortingng) qui devra impliquer des allocations de tas à lire dans la mémoire tampon souhaitée. Quand il s’agit de problèmes de stack / tas, la stack est toujours beaucoup plus rapide, donc si vous pouvez anticiper la taille maximale de la mémoire tampon nécessaire dans un cas particulier, une mémoire tampon de caractères simple sur la stack dépassera std :: ssortingng pour l’entrée (même si vous avez utilisé la réserve). Ceci est également vrai d’un tableau sur la stack par opposition à std :: vector, mais ces conteneurs sont mieux utilisés pour les cas où vous ne pouvez pas anticiper la taille à l’avance. Là où std :: ssortingng peut être plus rapide, il y a des cas où les gens pourraient être tentés d’appeler strlen de manière répétée, où stocker et conserver une variable de taille serait préférable.

Quant aux détails de gprof, il convient de souligner ces problèmes. Examinez-vous le graphe complet des appels, par opposition à un profil plat? Naturellement, le profil plat pourrait être trompeur dans ce cas. Il faudrait que je connaisse plus en détail comment vous utilisez gprof pour donner une meilleure réponse.

gprof uniquement des échantillons pendant le temps CPU, pas pendant le temps bloqué. Ainsi, un programme peut passer une heure à faire des E / S et une microseconde à calculer, et gprof ne verra que la microseconde .

Pour une raison quelconque, ce n’est pas bien connu.

Par défaut, les iostreams standard sont configurés pour fonctionner ensemble et avec la bibliothèque C stdio. En pratique, cela signifie que l’utilisation de cin et de cout pour des opérations autres que les entrées et sorties interactives a tendance à être lente.

Pour obtenir de bonnes performances avec cin et cout , vous devez désactiver la synchronisation avec stdio. Pour une entrée de haute performance, vous pourriez même vouloir détacher les stream.

Voir la question de stackoverflow suivante pour plus de détails.

Comment améliorer les performances d’IOStream?