Performance C++ vs C in Sachen Files



  • Hoihoi 🙂

    Da sehr oft über die Performance von C++ Streams gejammert wird und ich relativ zeitkritisch riesige Mengen Text lesen & parsen muss (es handelt sich um virtuelle Dateien, dh. die IO-Kapazitäten irgendeines Gerätes schränken nicht ein), wollte ich mal testen ob fscanf() gegenüber std::ifstream Geschwindigkeitsvorteile bietet.

    Das Resultat war dass 1.000.000 mal die /proc/[pid]/stat File unter Linux zu lesen & parsen 27.497s mit der C++ Lösung gedauert hat ... mit fscanf() waren es 28.651s.

    Wie kann das sein wenn die Streams doch so einen schlechten Ruf in Sachen Performance haben sollen? Kann ich definitiv nicht unterschreiben.

    Grüße,
    Ethon


  • Mod

    Ruf ist eben nicht alles. Wenn du auf jedes Gerücht im Internet hörst, müsstest du deinen Computer mittels Steckplatine programmieren für optimale Performance. Die C++ und die C Funktionen unterscheiden sich vor allem durch die Stärke ihrer Parsingmöglichkeiten. Die Streams kennen da in der Regel von Haus aus viel mehr mögliche Formate. Nun können grob gesagt 3 Fälle eintreten:
    1. Dein Programm ist Parserlastig und du benötigst anspruchsvolles Parsing: Bei den C Funktionen musst du nun eventuell fehlende Funktionalität hinzufügen während du die Streams direkt benutzen kannst. Beide Programme sollten gleich schnell sein, das C++ Programm ist einfacher zu entwickeln.
    2. Dein Programm ist Parserlastig und du benötigst kein anspruchsvolles Parsing: Die Streams verschwenden nun eventuell Zeit für Funktionen die gar nicht gebraucht werden, die C Funktionen sind daher schneller. Beide Programme sind ungefähr gleich schwer zu entwickeln.
    3. Dein Programm ist IO-lastig: Es ist egal ob man C++ oder C benutzt, eine Festplatte wird dadurch nicht schneller. Beide Programme sind gleich schnell.



  • Naja, die Dateien sind praktisch einfach nur einzulesen ... die stat-file sieht ja in etwa so aus:

    flo@ice:~/Projekte/ethonmem/tests/benchgetstatus$ cat /proc/self/stat
    3387 (cat) R 2445 3387 2445 34816 3387 4202496 247 0 0 0 0 0 0 0 20 0 1 0 659176 5636096 175 18446744073709551615 4194304 4247204 140735998812400 140737160937672 140520653464736 0 0 0 0 0 0 0 17 1 0 0 0 0 0

    Deswegen verwundert es mich schon irgendwie dass bei praktisch jedem Test die C++-Version die C Version abhängt.

    (Code muss ich wohl nicht zeigen, die C++-Version liest einfach per operator>>, die C mit fscanf und einem riesigen Formatstring.)



  • Der C-Formatstring muss ja auch erstmal geparst werden (zur Laufzeit) und dann die richtige Interpretation der Daten ausgewählt werden. Im op>> steht schon hartcodiert drin, wie die Daten interpretiert werden sollen, weil die richtige Überladung des op>> gewählt wird.


  • Mod

    Ethon schrieb:

    (Code muss ich wohl nicht zeigen, die C++-Version liest einfach per operator>>, die C mit fscanf und einem riesigen Formatstring.)

    Ich vermute mal das fällt unter Parserlastig. Du kannst zum Test ja mal die Eingabe aus dem Arbeitsspeicher kommen lassen anstatt aus einer echten Datei.



  • SeppJ schrieb:

    Ethon schrieb:

    (Code muss ich wohl nicht zeigen, die C++-Version liest einfach per operator>>, die C mit fscanf und einem riesigen Formatstring.)

    Ich vermute mal das fällt unter Parserlastig. Du kannst zum Test ja mal die Eingabe aus dem Arbeitsspeicher kommen lassen anstatt aus einer echten Datei.

    /proc ist ein virtuelles Dateisystem unter Linux um Usermode-Zugriff auf Kerneldaten zu ermöglichen, jede Datei wird standardmäßig im RAM gehalten.

    Aber danke. 😉



  • Das Ganze hängt auch noch von der verwendeten stream-Implementation ab. Ich habe vor längerer Zeit auch mal solche Geschwindigkeitsvergleiche gemacht. Da war STLPort etwa gleich schnell wie die C-Varianten, aber Dinkumware sehr viel langsamer (rund Faktor 3). Allerdings bei realen Dateien.



  • Dass die Streams einen schlechten Ruf in Bezug auf Performance haben, ist historisch bedingt - es gab eine Zeit, da waren die meisten iostream-Implementationen in der Tat deutlich langsamer als die entsprechenden C-Funktionen, und das hing in erster Linie mit ineffizienter Implementation der Locales-Subbibliothek zusammen. Bjarne Stroustrup verlinkt auf seiner Seite ein Papier aus dem Jahr 2003, in dem die Problematik und mögliche Lösungen beschrieben sind; der für iostreams relevante Teil ist 3.1 (ab Seite 61).

    Das ist jetzt knapp acht Jahre her, und diese Lösungen sind umgesetzt, daher gilt das Urteil nicht mehr.


Anmelden zum Antworten