Könnten fstreams schneller als FILE * sein?



  • könntest Du das bitte begründen. Was genau am iostream-Interface ist warum Schrott?

    Ein basic_streambuf Objekt hat eine locale - das macht keinen Sinn, zuunterst sollte etwas stehen was rein raw-io macht und nix von locales weiss -> sinnlose dependancy. Überhaupt ist das ganze basic_streambuf Interface IMHO unsauber, Input und Output schon auf unterster Ebene vermischt, weiter oben werden dann aber reine Input und reine Output Streams angeboten, huh? Die in und out Streams sind weitestgehend getrennt (z.B. unabhängig positionierbar), trotzdem pappt man as in ein Interface zusammen. Dann die Vermischung von Buffering und IO auf unterster Ebene - macht auch wenig Sinn.

    Dann die vermischung von "streams" (z.B. Sockets, Drucker, ...) und "random access IO" (Files, Memory-Buffer, ...), und wie schon erwähnt die Vermischung von Input-Only, Output-Only und Input/Output "streams" (bzw. "files"). Für soetwas sollte es getrennte Interfaces geben, und dann eben passende Adapter mittels denen ich aus einem "file" einen "stream" machen kann oder was auch immer.

    Also kurz: Die Trennung von IO, Buffering und "Formating" ist IMHO ungenügend, unsauber und unübersichtlich. Oder was volkard schon angesprochen hat, die ganzen State-Bits. Wieso gibts nicht eine Exception wenn ich was lesen will was nichtmehr da ist?

    Und dann die ganzen Namen OMG. "stossc", ja klar, versteht jeder auf Anhieb.

    ----

    Mit iostreams zu Arbeiten verbietet sich für mich in allen Fällen wo ich mehr machen muss/will als einfach bloss ein paar Strings/Zeichen in ein File zu schreiben bzw. zu lesen. Bevor ich mich tagelang mit iostreams rumärgere bei dem Versuch nen Socket, ein Stück NVRAM oder eine Serielle Schnittstelle mit streams zusammenzuknoten gehe ich lieber her und definiere meine eigene kleine Klassenhierarchie.



  • Oder was volkard schon angesprochen hat, die ganzen State-Bits. Wieso gibts nicht eine Exception wenn ich was lesen will was nichtmehr da ist?

    Also Exceptions gibts ja in der stream lib, die mußt du aber dummerweise vorher einmal explizit einschalten, dann bekommst du deine Exceptions. Ist aus Kompatibilitätsgründen leider so, das die Statebits standardmäßig herhalten. Aber es gibt Exceptions.

    gehe ich lieber her und definiere meine eigene kleine Klassenhierarchie.

    Verbietet dir ja auch keiner. Aber vielleicht hilft das hier ja auch etwas:
    http://www.boost.org/libs/iostreams/doc/index.html



  • hustbaer schrieb:

    Also kurz: Die Trennung von IO, Buffering und "Formating" ist IMHO ungenügend, unsauber und unübersichtlich.

    👍



  • Wie FILE * und iostreams schreiben oder lesen, spielt eigentlich keine Rolle, denn in beiden Fällen greift man auf das OS zurück und wie das diese Aufgaben erledigt, kann der Programmierer sowieso nicht beeinflussen.

    Die Frage stellt sich also ausschließlich in dem Bereich, solange man in C/C++ herumfrickelt.
    File-Streams sind in meinen Augen "gefühlt" schneller. Warum "gefühlt"? Weil ich nicht jedes Programm zweimal schreibe, nur um herauszufinden, was schneller ist.
    Also überlegen wir uns einfach mal was praktisches.

    Jeder Operator ist eine Funktion, ob sie nun "Schiebe( irgendwas )" oder "operator <<( irgendwas )" heißt, spielt dabei erstmal keine Rolle, Funktion ist Funktion, auch wenn sie operator heißt.

    Funktionen muss man rufen, Also Daten auf'n Stack packen, Register sichern, in die Funktion springen, Daten aus dem Stack holen, Ausgeben, Zurückspringen, Register zurücksetzen, Stack zurücksetzen.

    std::cout << "Hallo Welt" << std::endl;
    

    ist ein Ausdruck mit zwei Operatoren, also erstmal minimum 2 Funktionsaufrufe:

    operator << (std::out, "Hallo Welt" );
    operator << (std::out, std::endl );
    

    Diese Funktionsaufrufe sind freundlicherweise nicht virtuell. Immerhin etwas. Trotzdem punktet die Variante mit dem FILE * hier erstmal.

    printf( "%s\n", "Hello Welt" );
    

    Ein Funktionsaufruf, kopiert einen String auf die Ausgabe jedesmal, wenn man ein '%' entdeckt, wird statt des Strings das entsprechende Argument ausgedruckt.
    Die Umwandlung von (int) nach (char 😉 müssen beide übernehmen, von daher ändert sich hier auch nichts, was die Ausgabe angeht.

    Statt 1 Funktionsaufrufe bei printf() stehen also zwangsweise und unveränderlich x Funktionsaufrufe bei den IOStreams da. Da ist also auch nix dran zu verbessern. Aber nehmen die wirklich viel Zeit in Anspruch?

    Eigentlich nicht... aber wer benutzt bei iostreams schon Char-Arrays?
    Stattdessen vielleicht eher Objekte wie std::string, die nicht einfach wie bei scanf() beschrieben werden, sondern ordentlich per Konstruktor( noch ein Funktionsaufruf... ) erzeugt werden, dann Speicher besorgen ( Systemcall... ) und beim Verlassen des Kontext wieder per Destruktor zerstört werden ( Funktionsaufruf und SystemCall... ).

    Natürlich kann man einen std::string wie ein char-Array auch wiederverwenden, aber dann muss die Größe überprüft werden, ob der neue Inhalt überhaupt da reinpasst, gegebenenfalls neuer Speicher angefordert werden (Systemcall...) und der alte freigegeben werden (Systemcall...).

    scanf() packt die Daten in ein Array und fertig. Für das Ziel ist kein Call erforderlich, für die Quelle wird für's lesen genauso ein SystemCall erforderlich, wie beim IOStream.

    Hier geht massiv Geschwindigkeit verloren, dafür gewinnt man Sicherheit.

    Fazit: Wer einfache Routinen schreibt, mal eben was ausgeben will, ist mit printf() gut bedient. Wer komplexe Sachen schreiben möchte und nicht ganz sicher ist, dass er das mit scanf() und readf() usw. richtig hinbekommt, für den sind die iostreams sehr empfehlenswert.

    Lieber langsam als falsch.
    Der Vorteil bei den IOStreams ist wohl eher in der Lesbarkeit des Codes zu sehen. Der Nachteil dabei, dass der Formatstring verloren ging und die Sache etwas langsamer wird.

    Aber es ist in meinen Augen technisch absolut unmöglich, dass iostreams jemals so schnell wird, wie FILE *.

    Wie immer gilt, was besser ist, bestimmt das Geschick des Programmierers und die Anwendung, die er zu schreiben hat.

    PS: Ich bitte mein Posting wohlwollend aufzunehmen, dank diesem Posting habe ich jetzt meine EBay Auktion verpasst *grummel*



  • Nach meinen Überlegungen müsste eigentlich iostream schneller sein, als printf. Um z. B. einen int auszugeben, rufe ich mit printf eine Funktion auf. Diese parst erst mal den Formatstring. Und genau das kostet Zeit. Mit dem ostream-Operator für int wird direkt die richtige Routine angesprungen. Das gilt um so mehr, je mehr ich ausgebe.

    Andererseits stimmt das nicht so ganz mit den iostreams. Die Routine, die angesprungen wird, schreibt ja nicht direkt auf den Filedeskriptor, sondern in ein std::streambuf. Und erst diese führt die Ausgabe durch.

    Das bietet allerdings einen enormen Vorteil: der std::streambuf muß kein Filedeskriptor sein, sondern ist austauschbar.

    Ich muß allerdings zugeben, auch wenn ich ein Anhänger von iostreams bin, das das Interface tatsächlich nicht so glücklich ist.

    Übrigens habe ich mal einen Test unter Solaris (fragt mich nicht nach Version oder Ausstattung) gemacht. Da war printf geringfügig schneller, was ich verwunderlich fand. Ich kann mir das nur so erklären, daß printf einfach hoch optimiert ist. Der Parser für den Formatstring ist möglicherweise in hochoptimierten Assembler geschrieben, da er sehr oft verwendet wird.

    Tntnet



  • Ich persönlich bin mit iostream noch nie wegen der Performance gegen die Wand gefahren.
    Was sind denn das für Situationen in denen iostream zu langsam ist?
    1998 ,als nen PC 400 Mhz und 64MB RAM hatte, ist jeder gut mit den stream Klassen klar gekommen.8 Jahre später,wo die Prozessoren 10 mal schneller sind, fällt auf einmal Gott und der Welt auf wie schlecht und langsam doch die stream Klassen sind? 😕
    Ich mach mir lieber über andere (wichtige) Dinge Gedanken.
    Die ganze Diskussion sieht für mich eher nach ner Mischung aus Langeweile und der aktuellen Tendenz ,aus C++ ne Wissenschaft zu machen, aus.

    Gruß Spacelord



  • Xin schrieb:

    PS: Ich bitte mein Posting wohlwollend aufzunehmen, dank diesem Posting habe ich jetzt meine EBay Auktion verpasst *grummel*

    Schon wieder 'n Regal weg *SCNR* 😃 😉 ?

    Spacelord schrieb:

    Was sind denn das für Situationen in denen iostream zu langsam ist?

    Wie du als aufmerksamer Leser sicherlich bemerkt hast, ging es darum herauszufinden, wieso fstreams (+std::string) normalerweise etwas langsamer als FILE * sind und ob man das umkehren könnte. Kein einziger Post hat "fstreams sind zu langsam" als Inhalt.



  • Naja, ich hab dein Startposting auch so aufgefasst, das du fstreams zu langsam hälst. Jetzt wo du es explizit nochmal sagst und ich nochmal dein Startpostinglesen, sehe ich das du _nebenbei_ in _Klammern_ die Strings erwähnst.



  • Xin schrieb:

    Wie FILE * und iostreams schreiben oder lesen, spielt eigentlich keine Rolle, denn in beiden Fällen greift man auf das OS zurück und wie das diese Aufgaben erledigt, kann der Programmierer sowieso nicht beeinflussen.

    es geht um die bremsen außerhalb des bs.

    Die Frage stellt sich also ausschließlich in dem Bereich, solange man in C/C++ herumfrickelt.
    

    wir reden weder von C noch von frickeln.

    Jeder Operator ist eine Funktion, ob sie nun "Schiebe( irgendwas )" oder "operator <<( irgendwas )" heißt, spielt dabei erstmal keine Rolle, Funktion ist Funktion, auch wenn sie operator heißt.

    Funktionen muss man rufen, Also Daten auf'n Stack packen, Register sichern, in die Funktion springen, Daten aus dem Stack holen, Ausgeben, Zurückspringen, Register zurücksetzen, Stack zurücksetzen.

    schonmal was von inline gehört?

    Ein Funktionsaufruf, kopiert einen String auf die Ausgabe jedesmal, wenn man ein '%' entdeckt, wird statt des Strings das entsprechende Argument ausgedruckt.

    und ein if ist etwas langsamen. falsch vorhergesagte sprünge sind teuer. logo kann es schneller sein, wenn die typinformation dem compiler bekannt ist, statt if-orgien zu basteln. es gibt auch gut ausgemessene beispiele, wo kleine funktionen schneller sind als eine große funktion. eigentlich gehen alle technischen argumente an streams, die so ähnlich wie die aus der standardbibliothek sind. man müßte halt die ganzen fehlentscheidungen im design ignorieren und sie reimplementieren ohne schnickschnack.



  • GPC schrieb:

    Xin schrieb:

    PS: Ich bitte mein Posting wohlwollend aufzunehmen, dank diesem Posting habe ich jetzt meine EBay Auktion verpasst *grummel*

    Schon wieder 'n Regal weg *SCNR* 😃 😉 ?

    Trainierst Du als Gedächtniskünstler? ;-))

    OpenGL Handbücher, die für 9 Euro weggingen... nicht mehr ganz aktuell, aber für mal damit zu spielen besser als 80 Euro auszugeben.

    volkard schrieb:

    Xin schrieb:

    Wie FILE * und iostreams schreiben oder lesen, spielt eigentlich keine Rolle, denn in beiden Fällen greift man auf das OS zurück und wie das diese Aufgaben erledigt, kann der Programmierer sowieso nicht beeinflussen.

    es geht um die bremsen außerhalb des bs.

    Yepp, wie ich - bezogen auf vorherige Postings - schon schrieb, es spielt keine Rolle, was das OS macht, weil es gar nicht zum Thema gehört.

    volkard schrieb:

    Die Frage stellt sich also ausschließlich in dem Bereich, solange man in C/C++ herumfrickelt.
    

    wir reden weder von C noch von frickeln.

    printf frickelt sich in C recht gut und printf gehörte doch zum Thema?!
    Mir scheint, als wäre Dein Posting an einem Regentag entstanden?

    volkard schrieb:

    Funktionen muss man rufen, Also Daten auf'n Stack packen, Register sichern, in die Funktion springen, Daten aus dem Stack holen, Ausgeben, Zurückspringen, Register zurücksetzen, Stack zurücksetzen.

    schonmal was von inline gehört?

    Yepp, auch gerne und häufig für kleine Dinge verwendet.
    Wenn man allerdings jede Ausgabe inline erklärt, dann sollte man sich nicht wundern, wenn das Programm mitunter recht groß wird.

    Deklarierst Du Deine operator <<( std::ostream, <??> ) alle inline?

    volkard schrieb:

    Ein Funktionsaufruf, kopiert einen String auf die Ausgabe jedesmal, wenn man ein '%' entdeckt, wird statt des Strings das entsprechende Argument ausgedruckt.

    und ein if ist etwas langsamen. falsch vorhergesagte sprünge sind teuer.

    Öhm... argumentierst Du hier grade für meine Aussage oder gegen meine Aussage? In meinen Augen sollte das ironisch klingen - dann passt es aber nicht recht zum bisherigen Posting!?
    Mir jedenfalls fällt es schwer, eine kleine Schleife im Prozessorcache mit dem Aufwand von mehreren Funktionsaufrufen zu verbessern.

    volkard schrieb:

    logo kann es schneller sein, wenn die typinformation dem compiler bekannt ist, statt if-orgien zu basteln.

    Korrekt, sobald exakt eine Ausgabe getätigt wird und nichts zusammengebastelt wird, kann iostreams schneller als printf sein.
    Üblicherweise gibt man aber "Ergebnis: 4711" aus und nicht nur "4711" und schon wird die Sache wieder kompliziert...

    volkard schrieb:

    es gibt auch gut ausgemessene beispiele, wo kleine funktionen schneller sind als eine große funktion.

    Ausgemessene Beispiele gibt es für alles. Mit den richtigen Beispielen kann man alles beweisen. Die Frage verstand ich so, dass nicht ausgemessene Beispiele gesucht werden, sondern die Möglichkeit IOStreams soweit aufzubohren, dass sie schneller als FILE-Streams arbeiten.

    Wenn jeder operator << inline deklariert werden muss, um mit printf mitzuhalten, dann ist das sicherlich schön, aber konstruiert und nicht Alltag.

    Also korrigiere ich meine Aussage, dass es Ausgaben mit IOStreams geben kann, die schneller als printf() arbeiten.
    Dann haben sie genau 1 Ausgabe zu tätigen und sind auf diesen Typ spezialisiert. Eine spezialisierte Funktion gibt es bei den FILE-Streams nur für Binär/Text-Daten: fwrite().
    Es muss ja nicht immer printf() sein...
    Würde man den kompletten Inhalt von fwrite nun inline in jede Spezialisierung von operator <<( ... ) packen, dann, ja dann, könnte ein an dieser Stelle ein Geschwindkeitsvorteil von einem gesparten Funktionsaufruf entstehen - solange man fwrite nicht auch inline in eigene Spezialisierungsfunktionen packt.

    Noch konstruiertere Beispiele fallen mir grade nicht mehr ein, das würde eh nie einer mit gesundem Menschenverstand implementieren. Nebenher, wer erlaubt IOStreams zu optimieren, muss auch erlauben FILE-Streams zu optimieren, eine fwriteint() wäre wieder schneller als eine operator << ( std::ostream, int ).

    Denn es bleibt noch eines: Man muss sich noch die virtuelle Struktur der IO Handles bewegen während man das FILE-Handle nicht erst aus dem ostream-Interface ausgraben müsste. Da hilft auch kein inline oder das Ausweichen auf OS-Funktionen mehr.

    Etwas abstrakter: Man kann IOStreams austauschen. Ein IOStream ist also etwas virtuelles, während ein File-Handle nicht austauschbar, dafür direkt vorliegt. Virtuell ist immer (etwas) langsamer als direkt. Optimiert man sich an beidem tot, werden die FILE-Streams immernoch schneller sein. Sie sind eben auf Files optimiert, was bei den IOStreams eben nicht geht.

    Im Alltag werden die Prüfungen für verschiedene Streams und die regelmäßigen Funktionsaufrufe vermutlich eher ins Gewicht fallen, als die virtuellen Funktionen.
    Am Schluss bleibt: Bezogen auf die Geschwindkeit ziehen die IOStreams überall den Kürzeren. Dies zugunsten des Mehrwertes, den man von IOStreams erwartet - sofern man ihn überhaupt benötigt.
    Beides hat also eine Existenzberechtigung.



  • wenn du mit FILE* noch das alte fscanf rumgequäle meinst dann nehm ich ein paar femtosekunden gerne in kauf


Anmelden zum Antworten