Ausgabe innerhalb einer while-Schleife



  • Fachman für Klaskugeln schrieb:

    Nimm <iostream> und nicht <iostream.h>
    Ich entsinne mich dass die alte Lib ein Flush nur explizit nach endl oder flush gemacht hat, die neue nach jeder Ausgabe.

    Das ist nicht so definiert. Solange ich keinen flush mache, muß cout auch nichts ausgeben, kann es aber. Und das ist unabhängig davon, ob die alte oder neue Spezifikation verwendet wurde. Mag sein, daß bei einem bestimmten Compiler das Verhalten so ist. Bei einem anderen kann das genau umgekehrt sein.

    Man sollte sich angewöhnen, immer flush aufzurufen, wenn eine Ausgabe gewünscht ist. Das kann allerdings auch implizit erfolgen. Beispielsweise führt der std::endl-Manipulator nach der Zeilenschaltung auch einen flush aus.

    Also:

    std::cout << "Hallo\n"; // könnte was ausgeben, muß es aber nicht
      std::cout << "Hallo" << std::endl;  // gibt auf jeden fall was aus
    

    Bei mehrzeiligen Ausgaben habe ich mir angewöhnt, nur am Ende ein std::endl zu verwenden:

    std::cout << "Das ist eine\n"
                << "mehrzeilige\n"
                << "Ausgabe" << std::endl;
    

    Das überläßt es dem Compiler, wann es einen Systemaufruf macht. Das kann die Performance deutlich verbessern.

    Übrigens möchte ich an dieser Stelle eine statische Funktion im std::ios erwähnen: std::ios::sync_with_stdio(bool). Bei gcc (zumindest bei den Versionen, die ich getestet habe) wird ohne diesen Aufruf jedes Zeichen mittels Systemaufruf ausgegeben. Nach einem std::ios::sync_with_stdio(false) wird gepuffert, was die Geschwindigkeit beträchtlich steigert. Wird im Programm kein printf und Konsortien verwenden (was in C++-Programmen nicht sein sollte), sollte man das direkt am Anfang von main einfügen.

    Tommi



  • Vielen Dank für eure Tipps, ich habe es nun hinbekommen in dem ich die Variante 1 von CStoll verwendet habe, also:

    //1: flush()-Methode:
    while(...)
    {
      cout<<"*";
      cout.flush();
      ...
    }
    

    Nochmals Danke.



  • Ach so,

    eine Frage habe ich noch.
    Wirkt sich das Erzwingen der Ausgabe negativ auf die Performance der Programme aus oder ist das bei lediglich einem Ausgabe-Befehl nicht so wild?



  • Wenn du dir wirklich ernsthaft Sorgen um die Performance machst, solltest du die Ausgabe komplett weglassen (und nur vor der Schleife ein "Bitte warten" hinschreiben).



  • Das Problem ist, dass die Schleife wiederholt wird in einer Dimension, wo es in den 2-Stelligen Millionenbereich geht. Wenn dort was schief geht, dann wartet man bis an sein Lebensende 😉

    Aber andererseits könnte ich mir vorstellen, dass die Ausgabe von Millionen von * sich auch auf die Performance auswirkt. Ich kann halt nur nicht einschätzen in welchem Maße und ob es sich überhaupt lohnt sich da Gedanken zu machen oder ob es nicht der Rede wert ist. Erste Idee wäre nun von mir bei jeder 1000ten Iteration ein Sternchen auszugeben.



  • Die Ausgabe bremst in der Tat gewaltig, aber wenn du nur alle paar Sekunden eins ausgibst, kannst du das vernachlässigen.

    Viel komischer finde ich es, dass du weißt, dass dein Programm in eine Endlosschleife geraten kann, aber nichts dagegen machst 😕



  • zum einen sollten endlosschleifen abgefangen werden, zum anderen ist eine ausgabe in jeder iterationen bei millionen von schritten nicht nur tödlich sondern fahrlässig 😉

    paar millionen schleifendurchläufe sind nicht weiter wild, aber in jedem durchlauf was in die konsole zu schreiben, macht dann programm extrem lahm.



  • Ein flush verlangsamt schon den Programmablauf, aber so lange auf die Konsole geschrieben wird, ist das nicht weiter tragisch. Auf der Konsole sollte sowieso nur so viel Inhalt landen, was auch sinnvoll für den menschlichen Betrachter zu interpretieren geht.

    Wenn Du schon so einen Fortschrittsanzeige programmierst, gehe ich davon auch, daß eine Iteration eine gewisse Zeit in Anspruch nimmt und dann die Ausgabe nicht weiter ins Gewicht fällt. Interessant ist die Performancebetrachtung nur, wenn die Ausgabe umgeleitet wird.

    Ich habe mal einen kleinen Test gemacht. Folgendes Programm:

    #include <iostream>
    int main(int argc, char* argv[])
    {
      std::ios::sync_with_stdio(false);
      std::cout << std::cin.rdbuf();
    }
    

    Wie schon erwähnt bewirkt dieses sync_with_stdio, daß die Ausgabe gepuffert wird. Ohne wird jedes Zeichen einzeln geschrieben.

    Übersetzt mit

    g++ -o ttt -O2 ttt.cpp
    

    getestet habe ich das Programm mit:

    time dd if=/dev/zero bs=65536 count=16|./ttt|wc -c
    

    Ohne sync_with_stdio(false) benötgt das Programm 0,705s, mit 0,024s. Das ist so in etwa Faktor 30. Und da ist der Programmstart und der Aufruf von wc auch noch drin. Das sollte einem doch zu denken geben.

    Tommi



  • Also ich habe alles getan, damit das Programm nicht in eine Endlosschleife gerät. Allerdings habe ich das Programm noch nicht anhand einer so großen Anzahl von Iterationen getestet, da mir die Testdaten in der Größenordnung noch fehlen.

    Was würden ihr denn vorschlagen, soll ich gegen mögliche Endlosschleifen tun?
    Die Frage mag euch vielleicht komisch vorkommen, aber ich bin Programmiertechnisch noch nicht so lange dabei und kenne daher nicht annährend die kompletten Möglichkeiten die C++ bietet.



  • Das hängt vor allem davon ab, was du eigentlich vorhast. Schau dir die Abbruchbedingung deiner Schleife an - und dann überleg dir, ob und wann es möglich ist, daß diese Bedingung nie eintritt.



  • Was erwartest Du darauf für eine Antwort? 😉 Natürlich musst Du dafür sorgen, dass die Abbruchbedingung irgendwann erfüllt ist. Bei Zählschleifen sollte das eigentlich immer irgendwann gegeben sein.

    Ein Sprachmittel welches dafür sorgt "ab 20 Mio. Durchläufen betrachte ich es als Endlosschleife" gibt es jedenfalls nicht. Warum auch, es könnte ja sein dass die Schleife nach 21 Mio. Durchläufen beendet wird 😉



  • Es geht mir ja nicht nur um die Abbruchbedingung der While-Schleife, denn da innerhalb dieser sehr viele Methoden aufgerufen werden, könnte auch einer dieser Methoden unerwartetes tun und so eine Endlosschleife verursachen. Naja, ich schau mal.

    Übrigends dickes RESPEKT für die unglaublich schnellen Antworten 👍



  • Hast du diese Methoden auch selber geschrieben? Wenn ja, kannst du sie dir mal einzeln ansehen. Zwei Probleme könnten zu einer Endlosschleife führen:

    * Schleifenstrukturen ohne Abbruch (im einfachsten Fall "while(true)...", aber meist ist das etwas verborgener)
    * Rekursionen (die Funktion ruft sich direkt oder indirekt selbst wieder auf)

    (im ersten Fall steckt das Programm "nur" fest, im zweiten Fall wird es irgendwann abstürzen, wenn der Programmstack zusammenbricht)


Anmelden zum Antworten