<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[std::cout ist langsam! Stimmt es wirklich? (Ein kleiner Test)]]></title><description><![CDATA[<p>Hallo,</p>
<p>Oft hört man ja std::cout und Konsorten (std::clog, std::cerr) hätten im direkten Verglich mit std::printf und seinen Abwandlungen keine Chance (zumindest im Bezug auf Schnelligkeit. Dass sie typsicher und erweiterbar sind, ist natürlich ihr großer Vorteil). Genauso oft taucht allerdings das Argument auf, dass std::cout durch ein höheres Maß an Typinformationen eigentlich schneller als std::printf, das zuerst den Formatstring parsen muss, sein müsste.</p>
<p>Zumindest bei meinem Kompiler (VC++ 2008 EE) ist std::cout im Vergleich zu std::printf einfach nur langsam. Ich fragte mich also, woran das liegt. Nachdem ich mir die std::basic_ostream Klasse angesehen hatte, erkannt ich, dass die Typinformationen sehr wohl genutzt wurden. Zur Umwandlung von bestimmten Variablen in Strings wird ein Facet mit aktuellem Locale benutzt.</p>
<p>Was bleibt da noch übrig? Ein eigenes Locale schreiben um herauszufinden, ob das der Flaschenhals ist, war mir zu aufwendig. Außerdem zeigten kleine Profilingtests das die meiste Zeit in den Methoden des internen Streambuffers verwendet wurde. Folglich arbeitete ich mich ein wenig in Streambuffer ein und habe eine eigene ConsoleBuffer Klasse geschrieben, die auf OS-spezifischen Funktionen beruht (Ich wollte ein schnelles std::cout erschaffen). Da ich nur Windows habe, benutzt mein Buffer intern <a href="http://msdn2.microsoft.com/en-us/library/ms687401.aspx" rel="nofollow">WriteConsole</a>.</p>
<p>Letzten Endes war das einfügen des Buffers in std::cout dann eine Kleinigkeit:</p>
<pre><code class="language-cpp">std::cout.rdbuf(&amp;console_buffer)
</code></pre>
<p>Daraufhin folgte ein kleines Benchmark. Ich habe std::cout mit normalem Puffer, std::printf, std::puts und std::cout mir meinem Puffer verglichen. Erwartet hatte ich ungefähr Folgendes:</p>
<ul>
<li>4. std::cout (normal)</li>
<li>3. std::cout (mein Puffer)</li>
<li>2. std::printf</li>
<li>1. std::puts</li>
</ul>
<p>Ich erhoffte mir einen kleinen Vorsprung vor dem normalen Puffer. std::puts hielt ich für schneller als std::printf, da es den String nicht nach Formatzeichen parsen musste.</p>
<p>Die tatsächlichen Ergebnisse sind aber ein wenig anders. Hier mal ein Ergebnis bei dem ein String mit einer Länge von 247 Zeichen (hat sich so ergeben) 20.000 mal ausgegeben wurde (auf die Konsole):</p>
<ul>
<li>std::cout (normal Buffer) : 41.968s</li>
<li>std::printf : 1.672s</li>
<li>std::puts : 2.094s</li>
<li>std::cout (dons::ConsoleBuffer): 1.687s</li>
</ul>
<p>Andere Tests lieferten im Verhältnis gleiche Ergebnisse. Erstaunlich ist, das puts langsamer als das parsende printf ist und das std::cout fast so schnell wie printf ist. Interessant wird es wohl erst, wenn Variablen anderen Typs ausgegeben werden und printf parsen muss. Dafür hatte ich bisjetzt aber leider noch keine Zeit.</p>
<p>Den Geschwindigkeitsunterschied zwischen den verschiedenen Puffern führe ich momentan auf die Thread-Sicherheit des normalen Puffers zurück. Einen so großen Unterschied (Faktor ca. 25) hatte ich allerdings nicht erwartet. Ist zwar jetzt Implementationsabhängig, aber, wenn jemand den Grund hierfür kennt, bin ich immer daran interessiert.</p>
<p>Wenn jemand Interesse an dem Code hat, stelle ich ihn hier gerne rein (zu finden <a href="http://www.file-upload.net/download-715761/Sources.zip.html" rel="nofollow">hier</a>). Auch Kritik ist dann natürlich erwünscht, da ich davon ausgehe, dass ich irgendwo grobe Fehler gemacht habe, die irgendwann zu undefiniertem Verhalten führen oder nicht einem Standard Streambuffer gerecht werden, usw.</p>
<p>Gruß<br />
Don06</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/207585/std-cout-ist-langsam-stimmt-es-wirklich-ein-kleiner-test</link><generator>RSS for Node</generator><lastBuildDate>Sun, 11 Oct 2026 07:01:15 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/207585.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 09 Mar 2008 15:47:03 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to std::cout ist langsam! Stimmt es wirklich? (Ein kleiner Test) on Sun, 09 Mar 2008 16:38:00 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>Oft hört man ja std::cout und Konsorten (std::clog, std::cerr) hätten im direkten Verglich mit std::printf und seinen Abwandlungen keine Chance (zumindest im Bezug auf Schnelligkeit. Dass sie typsicher und erweiterbar sind, ist natürlich ihr großer Vorteil). Genauso oft taucht allerdings das Argument auf, dass std::cout durch ein höheres Maß an Typinformationen eigentlich schneller als std::printf, das zuerst den Formatstring parsen muss, sein müsste.</p>
<p>Zumindest bei meinem Kompiler (VC++ 2008 EE) ist std::cout im Vergleich zu std::printf einfach nur langsam. Ich fragte mich also, woran das liegt. Nachdem ich mir die std::basic_ostream Klasse angesehen hatte, erkannt ich, dass die Typinformationen sehr wohl genutzt wurden. Zur Umwandlung von bestimmten Variablen in Strings wird ein Facet mit aktuellem Locale benutzt.</p>
<p>Was bleibt da noch übrig? Ein eigenes Locale schreiben um herauszufinden, ob das der Flaschenhals ist, war mir zu aufwendig. Außerdem zeigten kleine Profilingtests das die meiste Zeit in den Methoden des internen Streambuffers verwendet wurde. Folglich arbeitete ich mich ein wenig in Streambuffer ein und habe eine eigene ConsoleBuffer Klasse geschrieben, die auf OS-spezifischen Funktionen beruht (Ich wollte ein schnelles std::cout erschaffen). Da ich nur Windows habe, benutzt mein Buffer intern <a href="http://msdn2.microsoft.com/en-us/library/ms687401.aspx" rel="nofollow">WriteConsole</a>.</p>
<p>Letzten Endes war das einfügen des Buffers in std::cout dann eine Kleinigkeit:</p>
<pre><code class="language-cpp">std::cout.rdbuf(&amp;console_buffer)
</code></pre>
<p>Daraufhin folgte ein kleines Benchmark. Ich habe std::cout mit normalem Puffer, std::printf, std::puts und std::cout mir meinem Puffer verglichen. Erwartet hatte ich ungefähr Folgendes:</p>
<ul>
<li>4. std::cout (normal)</li>
<li>3. std::cout (mein Puffer)</li>
<li>2. std::printf</li>
<li>1. std::puts</li>
</ul>
<p>Ich erhoffte mir einen kleinen Vorsprung vor dem normalen Puffer. std::puts hielt ich für schneller als std::printf, da es den String nicht nach Formatzeichen parsen musste.</p>
<p>Die tatsächlichen Ergebnisse sind aber ein wenig anders. Hier mal ein Ergebnis bei dem ein String mit einer Länge von 247 Zeichen (hat sich so ergeben) 20.000 mal ausgegeben wurde (auf die Konsole):</p>
<ul>
<li>std::cout (normal Buffer) : 41.968s</li>
<li>std::printf : 1.672s</li>
<li>std::puts : 2.094s</li>
<li>std::cout (dons::ConsoleBuffer): 1.687s</li>
</ul>
<p>Andere Tests lieferten im Verhältnis gleiche Ergebnisse. Erstaunlich ist, das puts langsamer als das parsende printf ist und das std::cout fast so schnell wie printf ist. Interessant wird es wohl erst, wenn Variablen anderen Typs ausgegeben werden und printf parsen muss. Dafür hatte ich bisjetzt aber leider noch keine Zeit.</p>
<p>Den Geschwindigkeitsunterschied zwischen den verschiedenen Puffern führe ich momentan auf die Thread-Sicherheit des normalen Puffers zurück. Einen so großen Unterschied (Faktor ca. 25) hatte ich allerdings nicht erwartet. Ist zwar jetzt Implementationsabhängig, aber, wenn jemand den Grund hierfür kennt, bin ich immer daran interessiert.</p>
<p>Wenn jemand Interesse an dem Code hat, stelle ich ihn hier gerne rein (zu finden <a href="http://www.file-upload.net/download-715761/Sources.zip.html" rel="nofollow">hier</a>). Auch Kritik ist dann natürlich erwünscht, da ich davon ausgehe, dass ich irgendwo grobe Fehler gemacht habe, die irgendwann zu undefiniertem Verhalten führen oder nicht einem Standard Streambuffer gerecht werden, usw.</p>
<p>Gruß<br />
Don06</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1471018</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1471018</guid><dc:creator><![CDATA[Don06]]></dc:creator><pubDate>Sun, 09 Mar 2008 16:38:00 GMT</pubDate></item><item><title><![CDATA[Reply to std::cout ist langsam! Stimmt es wirklich? (Ein kleiner Test) on Sun, 09 Mar 2008 15:52:21 GMT]]></title><description><![CDATA[<p>Denke dein Testprogrammcode währe noch interessant.<br />
Dann könnte man auch optimieren <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1471021</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1471021</guid><dc:creator><![CDATA[phlox81]]></dc:creator><pubDate>Sun, 09 Mar 2008 15:52:21 GMT</pubDate></item><item><title><![CDATA[Reply to std::cout ist langsam! Stimmt es wirklich? (Ein kleiner Test) on Sun, 09 Mar 2008 15:54:19 GMT]]></title><description><![CDATA[<p>Don06 schrieb:</p>
<blockquote>
<p>Wenn jemand Interesse an dem Code hat, stelle ich ihn hier gerne rein. Auch Kritik ist dann natürlich erwünscht, da ich davon ausgehe, dass ich irgendwo grobe Fehler gemacht habe, die irgendwann zu undefiniertem Verhalten führen oder nicht einem Standard Streambuffer gerecht werden, usw.</p>
</blockquote>
<p>Selbstverständlich musst du dein Testprogramm mitangeben, wenn du hier Benchmarkergebnisse veröffentlichst. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>Wie soll man es denn sonst kontrollieren bzw. auf anderen Implementierungen testen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1471024</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1471024</guid><dc:creator><![CDATA[GNU-Fan]]></dc:creator><pubDate>Sun, 09 Mar 2008 15:54:19 GMT</pubDate></item><item><title><![CDATA[Reply to std::cout ist langsam! Stimmt es wirklich? (Ein kleiner Test) on Sun, 09 Mar 2008 15:56:30 GMT]]></title><description><![CDATA[<p>Don06 schrieb:</p>
<blockquote>
<p>Erstaunlich ist, das puts langsamer als das parsende printf ist...</p>
</blockquote>
<p>Anscheinend schreibt puts den String direkt zum Ausgabegerät und wartet auf eine Rückmeldung, bevor der nächste String gesendet werden kann. Printf formatiert die Ausgabe erstmal im Speicher (Pufferung, Daten sammeln) und braucht daher viel weniger Schreibzugriffe zur Hardware. Das wäre vielleicht eine Erklärung.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1471026</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1471026</guid><dc:creator><![CDATA[funky cat]]></dc:creator><pubDate>Sun, 09 Mar 2008 15:56:30 GMT</pubDate></item><item><title><![CDATA[Reply to std::cout ist langsam! Stimmt es wirklich? (Ein kleiner Test) on Sun, 09 Mar 2008 16:06:38 GMT]]></title><description><![CDATA[<p>Hier gibt es die <a href="http://www.file-upload.net/download-715761/Sources.zip.html" rel="nofollow">Sources</a>. Es fehlt noch jegliche Dokumentation und ein bisschen müsste man wohl noch überarbeiten, aber das seht ihr dann selbst.</p>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/1652">@funky</a> cat: Danke, das wäre dann natürlich logisch.</p>
<p>Gruß<br />
Don06</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1471030</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1471030</guid><dc:creator><![CDATA[Don06]]></dc:creator><pubDate>Sun, 09 Mar 2008 16:06:38 GMT</pubDate></item><item><title><![CDATA[Reply to std::cout ist langsam! Stimmt es wirklich? (Ein kleiner Test) on Sun, 09 Mar 2008 16:38:29 GMT]]></title><description><![CDATA[<p>hm - also ich hab dein program ausprobiert, allerdings den teil mit deinem streambuf weggelassen (unter linux) und NUMBER_OF_PRINTS auf 50000 verzehnfacht, weil die ausgabe sonst &lt;0.02 sekunden war, ergebnis:</p>
<pre><code>g++ (4.2.2) -Wall
std::cout (normal Buffer)      : 0.17s
std::printf                    : 0.38s
std::puts                      : 0.34s
</code></pre>
<p>dazu muss ich fairerweise sagen, dass der flaschenhals allein darin liegt, wie schnell meine konsole den text anzeigen kann:</p>
<pre><code>time -p ./main
std::cout (normal Buffer)      : 0.17s
std::printf                    : 0.38s
std::puts                      : 0.33s

real 17.24
user 0.16
sys 0.72
</code></pre>
<p>dabei komme ich mit gnome-terminal also auf 17.24 sekunden, das fast dreimal schneller ist als xterm (58.10s).</p>
<p>jetzt der direkte vergleich mit folgender änderung am programm:</p>
<pre><code class="language-cpp">#ifndef TEST
#error &quot;define TEST!&quot;
#endif 

int main()

{

	std::cout.sync_with_stdio(false);

	double times[4];

   times[TEST] = make_test(TEST);

	const char* const TEST_NAMES[] =

		{ &quot;std::cout (normal Buffer)      &quot;, 

		  &quot;std::printf                    &quot;, 

		  &quot;std::puts                      &quot; };

	std::cout &lt;&lt; '\n' &lt;&lt; std::endl;

   std::cout &lt;&lt; TEST_NAMES[TEST] &lt;&lt; &quot;: &quot; &lt;&lt; times[TEST] &lt;&lt; 's' &lt;&lt; std::endl;

	return 0;

}
</code></pre>
<p>die ergebnisse (gnome-terminal):</p>
<pre><code>g++ -Wall -DTEST=0 -o testcout
g++ -Wall -DTEST=1 -o testprintf
g++ -Wall -DTEST=2 -o testputs

time -p ./testcout

std::cout (normal Buffer)      : 0.17s
real 5.43
user 0.01
sys 0.16

time -p ./testprintf

std::printf                    : 0.36s
real 6.17
user 0.09
sys 0.27

time -p ./testputs

std::puts                      : 0.36s
real 5.91
user 0.04
sys 0.32
</code></pre>
<p>der flaschenhals liegt also eindeutig bei der jeweiligen konsole, die ich verwendet habe. die zeit, die cout, printf oder puts selbst brauchen, ist vernachlässigbar.<br />
warum deine implementation des cout-streambufs so langsam ist, kann dir wohl am besten die dokumentation deiner entwicklungsumgebung sagen (threadsafe? anderer overhead? funktionalität? vergessen, auf release zu schalten?)</p>
<p>abgesehen davon finde ich nicht, dass man bei einer text-ausgabe auf die geschwindigkeit achten sollte; ich habe zumindest noch niemanden gesehen, der 50000 wörter in fünf millisekunden lesen kann.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1471040</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1471040</guid><dc:creator><![CDATA[queer_boy]]></dc:creator><pubDate>Sun, 09 Mar 2008 16:38:29 GMT</pubDate></item><item><title><![CDATA[Reply to std::cout ist langsam! Stimmt es wirklich? (Ein kleiner Test) on Sun, 09 Mar 2008 16:53:00 GMT]]></title><description><![CDATA[<p>std::endl ist überflüssig.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1471051</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1471051</guid><dc:creator><![CDATA[--------]]></dc:creator><pubDate>Sun, 09 Mar 2008 16:53:00 GMT</pubDate></item></channel></rss>