Fehlerhaftes Verständnis von Templates ?
-
Cpp Tech schrieb:
// ... cout << endl << endl; // ...
Yeah. Ich würd' zur Sicherheit danach noch flushen:
cout << endl << endl << flush;
-
Swordfish schrieb:
Cpp Tech schrieb:
// ... cout << endl << endl; // ...
Yeah. Ich würd' zur Sicherheit danach noch flushen:
cout << endl << endl << flush;
Ich würde mehr Klammern setzen, bei endl immer umbrechen und das Semikolon dann verdoppeln, damit man sieht, daß die Zeile fertig ist.
(((cout << endl) << endl) << flush) ;
-
Herzlich Dank an alle für den Hinweis!
Im Namespace std gibt es eine Funktion max. Ich nehme an in deinem Code steht ein using namespace std, richtig? Das führt dann natürlich zu einem Konflikt. Deshalb: using namespace std pöse
Und tatsächlich, jetzt verstehe ich... Nachdem ich den Namen der Funktion geändert habe, funktionierte alles wie gewünscht.
Yeah. Ich würd' zur Sicherheit danach noch flushen:
cout << endl << endl << flush;
Danke für den Rat, ich kannte den Manipulator "flush" bisher noch gar nicht. Er leert den Puffer und lässt alle Ausgaben sofort erscheinen, wenn ich das richtig verstanden habe (Stichwort "sauberer" Programmcode)?
-
Cpp Tech schrieb:
Danke für den Rat, ich kannte den Manipulator "flush" bisher noch gar nicht. Er leert den Puffer und lässt alle Ausgaben sofort erscheinen, wenn ich das richtig verstanden habe (Stichwort "sauberer" Programmcode)?
Der Rat von Swordfish war nicht ernst gemeint, denn
std::endl
flushst automatisch. Lies einmal C++ Reference - std::endl, dann dürfte alles klar werden.
-
Mehr noch: Normalerweise willst du nicht flushen (also auch nicht endl), denn in allen gängigen Szenarien, wo du so etwas wünschen könntest, passiert es bereits automatisch, und in allen anderen Szenarien ist es überflüssiger Overhead.
-
Da es mich interessiert hat wie gross der Performanceunterschied sein kann habe ich versucht einen kurzen Benchmark zu schreiben.
Ein paar zufällige Integer werden zeilenweise in ein File geschrieben wobei zuerst'\n'
und anschliessendstd::endl
für den Zeilenumbruch verwendet wird.Hier der Code:
#include <chrono> #include <iostream> #include <fstream> #include <vector> int main(int argc, char *argv[]) { srand(time(nullptr)); if ( argc != 2 ) { std::cerr << "Usage: " << argv[0] << " " << "MB" << std::endl; exit(1); } uint64_t size = atol(argv[1]) << 20; std::vector<int> rand_data; for ( size_t i = 0; i < size / sizeof(int); ++i ) rand_data.push_back(rand()); uint64_t count,duration; std::chrono::time_point<std::chrono::system_clock> startP, endP; { startP = std::chrono::system_clock::now(); std::ofstream buffered_output("buffered.out"); for ( auto data : rand_data ) buffered_output << data << '\n'; endP = std::chrono::system_clock::now(); duration = std::chrono::duration_cast<std::chrono::nanoseconds>(endP-startP).count(); std::cout << "Using \\n:\t" << count << '\t' << (duration/1.0E9) << " sec \t" << (10000.0*size)/(duration) << " GB/s\n"; } { startP = std::chrono::system_clock::now(); std::ofstream buffered_output("unbuffered.out"); for ( auto data : rand_data ) buffered_output << data << std::endl; endP = std::chrono::system_clock::now(); duration = std::chrono::duration_cast<std::chrono::nanoseconds>(endP-startP).count(); std::cout << "Using endl:\t" << count << '\t' << (duration/1.0E9) << " sec \t" << (10000.0*size)/(duration) << " GB/s\n"; } }
Kompiliert habe ich ganz einfach mit
g++ -O2 -std=c++11 -o main main.cpp
Resultat fürr 10MB an Daten:
Using \n: 0 0.561771 sec 186.655 GB/s
Using endl: 0 72.7497 sec 1.44135 GB/sDer Unterschied ist ziemlich gross.
PS:
Ich habe kaum Erfahrung mit Benchmarking. Bin also für Feedback dankbar
-
Lustigerweise ist bei nem Stringstream genau umgekehrt. Zwar nicht so extrem wie bei Dateien, aber doch merklich.
-
Stimmt, ich hab obigen Code mit
stringstream
stattofstream
ausgeführt und folgendes erhalten:Using \n: 0 2.55661 sec 410.144 GB/s
Using endl: 0 2.36814 sec 442.785 GB/s
-
Skym0sh0 schrieb:
Lustigerweise ist bei nem Stringstream genau umgekehrt. Zwar nicht so extrem wie bei Dateien, aber doch merklich.
Du willst doch nur wieder endl schreiben.
size=1M Using \n: 0 0.0187179 sec 560.201 GB/s Using endl: 0 0.0176288 sec 594.808 GB/s size=10M Using \n: 0 0.184224 sec 569.184 GB/s Using endl: 0 0.178102 sec 588.749 GB/s size=100M Using \n: 0 1.90732 sec 549.764 GB/s Using endl: 0 1.84805 sec 567.395 GB/s size=1000M Using \n: 0 18.7715 sec 558.601 GB/s Using endl: 0 18.0149 sec 582.06 GB/s
size=1M Using endl: 0 0.0222931 sec 470.359 GB/s Using \n: 0 0.0218076 sec 480.831 GB/s size=10M Using endl: 0 0.177248 sec 591.587 GB/s Using \n: 0 0.185553 sec 565.109 GB/s size=100M Using endl: 0 1.80715 sec 580.238 GB/s Using \n: 0 1.91158 sec 548.538 GB/s size=1000M Using endl: 0 17.784 sec 589.619 GB/s Using \n: 0 18.8306 sec 556.847 GB/s
edit: Uuups, hatte das Konstruktorargument (den Dateinamen) stehenlassen. Ihr auch?
size=1M Using endl: 0 0.0180045 sec 582.395 GB/s Using \n: 0 0.0191331 sec 548.044 GB/s size=10M Using endl: 0 0.178203 sec 588.418 GB/s Using \n: 0 0.188795 sec 555.406 GB/s size=100M Using endl: 0 1.84706 sec 567.699 GB/s Using \n: 0 1.94918 sec 537.956 GB/s size=1000M Using endl: 0 18.0015 sec 582.494 GB/s Using \n: 0 18.7693 sec 558.664 GB/s
-
Die GB/s sollten auf jedenfall nochmal überarbeitet werden. So schnell ist ja normalerweise nicht mal der L1-Cache.
-
Ich hab' mir auch gedacht dass hier irgendwo ein Rechenfehler drin sein muss.
War aber zu faul es nachzurechnen
-
Also für mich sieht das jetzt aber nicht so aus als ob
endl
so böse wäre wie hier oft dargestellt, da sind ja immer nur ca. 1-5% Unterschied?
-
happystudent schrieb:
Also für mich sieht das jetzt aber nicht so aus als ob
endl
so böse wäre wie hier oft dargestellt, da sind ja immer nur ca. 1-5% Unterschied?72.7497 zu 0.561771 sind 1-5%?
-
Bei Stringstreams ist der Unterschied nicht so gravierend, weil deren Synchronisation nichts mit dem OS zu tun hat ...
-
ASAP schrieb:
72.7497 zu 0.561771 sind 1-5%?
Nein, aber 18.7715 sec zu 18.0149 sec zum Beispiel. Oder sämtliche sonstigen Werte aus Volkarts Benchmark. Das
endl
ist da ja sogar schneller als das'\n'
. Von daher:Swordfish schrieb:
Bei Stringstreams ist der Unterschied nicht so gravierend, weil deren Synchronisation nichts mit dem OS zu tun hat ...
Was heißt "nicht so gravierend", es ist ja sogar anders rum.
-
Ich weiß nicht, was volkard gemessen hat. Aber der schlimmste Fall ist halt, wenn's eine Datei ist, was icarus2 auch gemessen hat.
-
Warum nicht einfach std::endl nie nehmen? Wenn wir von 500+-30 GB/s reden, wird's daran nicht liegen, wenn eine Anwendung schneckt.
Komische Streams, die selber zur Laufzeit schauen, ob '\n' geschickt wurde und dann in ihren Einstellungen nachschauen, ob sie dann fluschen müssen, reden wir von sowas? Falls ja, sind wir eigentlich bei der falschen Sprache oder dringend bei den falschen Streams. Da muss dann locker bleiben. Ohne Änderung am Code könnte man wenn man wöllte…
-
Swordfish schrieb:
Ich weiß nicht, was volkard gemessen hat. Aber der schlimmste Fall ist halt, wenn's eine Datei ist, was icarus2 auch gemessen hat.
Ich hab nur stringstream gemessen, alles im RAM und keine Auslagerungsdatei.
Bei Dateien macht endl locker meinen Intel-i7 zu einem Commodore-64-er.