Ausgabe innerhalb einer while-Schleife



  • Hallo Leute,

    ich möchte innerhalb einer while-Schleife pro Iterationschritt jeweils ein * ausgeben. Dies setze ich normalerweise durch ein einfaches cout << "*"; um. Das Problem ist aber nun, dass die Sterne erst dann angezeigt werden, nachdem alle Iterationen der while-Schleife durchlaufen wurden. Ich möchte jedoch, dass während der einzelnen Iterationen immer das Sternchen direkt ausgegeben wird und nicht erst nachdem die while-Schleife terminiert ist.

    Der Sinn dabei ist, dass innerhalb der while-Schleife ziemlich viele Methoden aufgerufen werden und es im schlimmsten Fall zu Endlos-Schleifen kommen könnte und ich daher das Sternchen als so eine Art "Processing-Anzeige" verwenden will mit Hilfe dieser ich feststellen kann, ob das Programm weiterarbeitet oder in eine Endlos-Schleife geraten ist. Ein neu hinzukommender Stern zeigt also quasi an, dass gerade ein neuer Iterationsschritt begonnen wurde.

    Danke und Viele Grüße
    Agamemnon



  • Codeausschnitt wo du hängst ???



  • Die While-Schleife hier rein zu kopieren würde wenig Sinn machen, da diese einige Methoden beinhaltet und der Quellcode des gesamten Projekts ca. 10.000 Zeilen beinhaltet.

    Vom Prinzip sieht es aber so aus:

    while(Bedingung == true)
    {
         cout << "*";
         methode1();
         methode2();
         ...
         methodeN();
    }
    

    Und ich möchte, dass das Sternchen bei jedem Durchlauf direkt ausgegeben wird. Bei dem Codeausschnitt ist es so, dass die * erst dann alle ausgegeben werden, wenn die Bedingung der While-Schleife nicht mehr erfüllt ist.



  • Bei dem CodeAusschnitt ist es so, das bevor alle Methoden jeweils durchlaufen werden ein "" ausgegeben wird.Möchtest du nach jeder durchlaufenen Methode ein "" haben, oder was ?



  • Oder verbiegst du in deinen Methoden den Ausgabestrom ???



  • Vielleicht bilde ich es mir ja auch nur ein, aber der Gag ist, dass eben nicht bei jeder Iteration sofort ein Stern ausgegeben wird, sondern alle auf einmal nach dem die Schleife terminiert.

    Die Schleife wird zum Beispiel 200x durchlaufen. Das dauert seine Zeit. Ich würde so auf 10 Sekunden tippen. Sind die 10 Sekunden um, so werden direkt die 200 * ausgegeben. Was ich aber will ist dass während der 10 Sekunden die Sterne einzeln ausgegeben werden. Quasi wie so eine Art Prozentanzeige.

    Zur Zeit sieht es so aus:
    Programm läuft und gibt dann nach Abarbeitung aller Iterationen ************************************** aus.

    Es soll aber so sein:
    1.Iteration: *
    2.Iteration: **
    3.Iteration: ***



  • ist das eine reine "einfache" konsolenanwendung oder verwendest du multithreading oder nen gui o.ä.?

    bei anderer als der standard resourcenverwaltung kann die ausgabe durch andere prozesse blockiert werden (sehr gerine priorität) und erst dann abgearbeitet, wenn mal wieder bisschen zeit ist.

    du kannst die ausgabe des buffers (std::cout ist so ein buffer) an einer bestimmten stelle allerdings erzwingen. der befehl dazu müsste flush() oder so ähnlich lauten.



  • 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.



  • Der Ausgabepuffer wird normalerweise dann geleert, wenn das Programm der Meinung ist, daß er voll ist (und die Ausgaben kommen erst auf den Monitor, wenn das der Fall ist). Als Lösung fallen mir drei Möglichkeiten ein:

    //1: flush()-Methode:
    while(...)
    {
      cout<<"*";
      cout.flush();
      ...
    }
    
    //2: flush-Manipulator:
    while(...)
    {
      cout<<"*"<<flush;
      ...
    }
    
    //3: Pufferung ausschalten:
    cout<<unitbuf;
    while(...)
    {
      cout<<"*";
      ...
    }
    


  • 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 😉


Log in to reply