Einleitung: Das Geschwindigkeitsparadoxon, das Stack Overflow sprengte
\n\nStellen Sie sich folgende Situation vor: Sie lösen eine Programmieraufgabe oder verarbeiten eine gigabytegroße Logdatei. Das Python-Skript ist in 2 Sekunden fertig. Sie schreiben es in C++ neu, erwarten eine zehnfache Beschleunigung, aber … erhalten 10 Sekunden! Ein bekanntes Problem? Genau diese Frage erhielt tausende Aufrufe auf Stack Overflow und löste eine legendäre Diskussion aus: „Why is reading lines from stdin much slower in C++ than Python?“.
\n\nWie kann es sein, dass das „schnelle“ C++ gegen das „langsame“ Python bei einer so trivialen Operation wie dem Lesen von Zeilen verliert? Die Antwort liegt nicht in der Geschwindigkeit der Sprache selbst, sondern in den Standardeinstellungen und der Architektur von iostream. In diesem Artikel führen wir unsere eigene Untersuchung durch, schreiben Testcode in C++ und Python, messen die Zeit und, vor allem, lernen wir, wie man die Ein-/Ausgabe in C++ wirklich schnell macht.
\n\nDieser Artikel ist keine trockene Theorie, sondern ein praktischer Leitfaden für alle, die in C++ programmieren und auf Probleme mit der Leistung der Ein-/Ausgabe stoßen. Los geht's!
\n\nDer Kern des Problems: Warum ist iostream „langsam“?
\n\nWenn Sie std::cin >> data oder std::getline(std::cin, line) schreiben, tut C++ standardmäßig etwas, von dem viele nicht einmal ahnen. Es synchronisiert seine Ein-/Ausgabeströme mit den Standard-C-Strömen (stdin, stdout). Warum? Aus Kompatibilitätsgründen: Sie können printf und std::cout gleichzeitig in einem Programm verwenden, und die Ausgaben vermischen sich nicht.
Diese Synchronisation ist teuer. Jeder Aufruf von cin oder cout überprüft den Zustand der C-Ströme, was eine schnelle gepufferte Operation in eine langsame synchrone verwandelt.
In Python ist alles anders. Die Funktionen input() und sys.stdin.readline() verwenden eine eigene, gut optimierte Pufferung auf C-Ebene. Keine unnötige Synchronisation – einfach nur das Lesen eines Datenblocks aus dem Dateideskriptor. Deshalb kann das Lesen von stdin in Python schneller sein als in C++ „von Haus aus“.
Experiment: Geschwindigkeitstest
\n\nLassen Sie uns das in der Praxis überprüfen. Wir schreiben ein einfaches Programm, das 1.000.000 Zeilen von stdin liest und nichts damit macht (nur einliest). Zuerst in C++ „wie es ist“:
\n\n// slow_cin.cpp\n#include <iostream>\n#include <string>\n\nint main() {\n std::ios::sync_with_stdio(false); // Zuerst auskommentieren\n std::cin.tie(nullptr); // Und das auch\n\n std::string line;\n while (std::getline(std::cin, line)) {\n // Nichts tun\n }\n return 0;\n}\n\nUnd jetzt in 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\nStarten wir den Test mit seq 1000000 | ./slow_cin und seq 1000000 | python3 fast_python.py. Das Ergebnis wird schockierend sein: C++ ohne Optimierungen kann 5-10 Mal langsamer sein als Python! Aber beeilen Sie sich nicht, C++ zu begraben – das Problem wird mit zwei Codezeilen gelöst.
Lösung: Zwei magische Zeilen
\n\nAlles, was nötig ist, um die Ein-/Ausgabe in C++ zu beschleunigen, ist, die Synchronisation und die Bindung der Ströme zu deaktivieren. Fügen Sie am Anfang von main() hinzu:
std::ios::sync_with_stdio(false);\nstd::cin.tie(nullptr);\n\nDie erste Zeile deaktiviert die Synchronisation zwischen iostream und stdio. Die zweite entkoppelt cin von cout (standardmäßig leert cout vor jeder Eingabeoperation den Puffer, was ebenfalls verlangsamt). Danach wird Ihr C++-Code genauso schnell wie Python arbeiten, oft sogar schneller.
Ergebnis überprüfen
\n\nJetzt kommentieren Sie diese Zeilen in unserem Test aus und starten ihn erneut. Sie werden sehen, dass die Leistung von C++ in die Höhe schießt. In einigen Benchmarks beträgt der Unterschied das 10-fache.