Introduction : Le paradoxe de la vitesse qui a explosé Stack Overflow
\n\nImaginez la situation : vous résolvez un problème de compétition ou traitez un fichier journal d'un gigaoctet. Le script Python s'exécute en 2 secondes. Vous le réécrivez en C++, en espérant une accélération décuplée, mais… vous obtenez 10 secondes ! Une douleur familière ? C'est exactement cette question qui a recueilli des milliers de vues sur Stack Overflow et a donné naissance à une discussion légendaire : « Why is reading lines from stdin much slower in C++ than Python? ».
\n\nComment se fait-il que le C++ « rapide » puisse perdre face au Python « lent » dans une opération aussi triviale que la lecture de lignes ? La réponse ne réside pas dans la vitesse du langage lui-même, mais dans les paramètres par défaut et l'architecture de iostream. Dans cet article, nous allons mener notre propre enquête, écrire du code de test en C++ et Python, mesurer le temps et, surtout, apprendre à rendre les entrées-sorties en C++ vraiment rapides.
\n\nCet article n'est pas une théorie aride, mais un guide pratique pour tous ceux qui écrivent en C++ et rencontrent des problèmes de performance des entrées-sorties. C'est parti !
\n\nLe cœur du problème : Pourquoi iostream « ralentit-il » ?
\n\nLorsque vous écrivez std::cin >> data ou std::getline(std::cin, line), C++ fait par défaut quelque chose dont beaucoup ne se doutent même pas. Il synchronise ses flux d'entrée-sortie avec les flux standard de C (stdin, stdout). Pourquoi ? Pour la compatibilité : vous pouvez utiliser simultanément printf et std::cout dans un même programme, et la sortie ne sera pas mélangée.
Cette synchronisation coûte cher. Chaque appel à cin ou cout vérifie l'état des flux C, transformant une opération tamponnée rapide en une opération synchrone lente.
En Python, c'est tout différent. La fonction input() et sys.stdin.readline() utilisent leur propre tampon, bien optimisé, au niveau du C. Pas de synchronisation superflue — juste la lecture d'un bloc de données depuis le descripteur de fichier. C'est pourquoi la lecture depuis stdin en Python peut être plus rapide qu'en C++ « prêt à l'emploi ».
Expérience : Test de vitesse
\n\nVérifions cela en pratique. Écrivons un programme simple qui lit 1 000 000 de lignes depuis stdin et ne fait rien avec (seulement les lire). D'abord en C++ « tel quel » :
\n\n// slow_cin.cpp\n#include <iostream>\n#include <string>\n\nint main() {\n std::ios::sync_with_stdio(false); // Commentons pour l'instant\n std::cin.tie(nullptr); // Et ceci\n\n std::string line;\n while (std::getline(std::cin, line)) {\n // Ne rien faire\n }\n return 0;\n}\n\nEt maintenant en Python :
\n\n# fast_python.py\nimport sys\n\ndef main():\n for line in sys.stdin:\n pass\n\nif __name__ == "__main__":\n main()\n\nLançons le test avec seq 1000000 | ./slow_cin et seq 1000000 | python3 fast_python.py. Le résultat sera choquant : le C++ sans optimisations peut être 5 à 10 fois plus lent que Python ! Mais ne vous précipitez pas pour enterrer le C++ — le problème se résout avec deux lignes de code.
Solution : Deux lignes magiques
\n\nTout ce dont vous avez besoin pour accélérer les entrées-sorties en C++ est de désactiver la synchronisation et la liaison des flux. Ajoutez au début de main() :
std::ios::sync_with_stdio(false);\nstd::cin.tie(nullptr);\n\nLa première ligne désactive la synchronisation entre iostream et stdio. La seconde détache cin de cout (par défaut, avant chaque opération d'entrée, cout vide son tampon, ce qui ralentit également le travail). Après cela, votre code C++ commencera à fonctionner au même niveau que Python, et souvent plus rapidement.
Vérifions le résultat
\n\nMaintenant, décommentez ces lignes dans notre test et relancez-le. Vous verrez que la performance du C++ décolle. Dans certains benchmarks, la différence atteint 10 fois.