File I/O : std::list oder std::vector oder std::deque ??????? (Performance)



  • asc schrieb:

    Mag für eine STL-Implementation stimmen, aber soviel ich weiß nicht zwangsweise für jede STL-Implementierung.

    kennst du eine mit implizitem sharing von daten?

    asc schrieb:

    Zum einen sind zusätzliche new/delete auch nicht performant, zum anderen: warum sollte der String dauernt kopiert werden: Er wird einmal rein- und einmal rauskopiert in seinen Anwendungsfall, sofern der Vektor mit einer sinnvollen Größe initialisiert wurde.

    da dieses kopieren (einmal rein und einmal raus) die hauptarbeit des programmes, das der op bauen will, ausmacht und man sie wegoptimieren kann, sollte man es auch tun.
    das es im prinzip völlig sinnlos ist, da die io eh um welten langsamer ist, schrieb ich bereits..

    asc schrieb:

    Und wenn du schon unbedingt mit Stringzeigern optimieren willst, kannst du gleich auf char* Pointer wechseln.

    kann man auch machen. ist aber von der performance reichlich irrelevant. so schlecht ist die performance der stringklasse dann doch nicht.



  • Lässt sich nicht schon beim einlesen sparen?

    typedef <container_nach_wahl<std::string> > container;
    container cont;
    ifstream in(argv[1]);
    std::string line,buffer;
    while(in.good())
    {
       for(int i=0; i < 200 && std::getline(in,line);i++)
          buffer = line + "\n" + buffer;
       cont.push_back(buffer);
       buffer.clear();
    }
    

    Setzt natürlich voraus das Stringoperationen schneller sind als push_back + iteration.

    phlox



  • dass die string-operationen schneller sind, bezweifle ich, da für diese kein amortisiert konstantes verhalten für die vergrößerung garantiert ist und wenn mich nicht alles täuscht, auch in den meisten nicht implementiert ist.
    es ist in der mehrheit der fälle auch so, dass die string-daten in einem zusammenhängenden array gespeichert werden. ist zwar vom standard nicht vorgeschrieben, sorgt aber dafür das anfügen an einem string meistens sehr teuer ist.



  • zunaechst einmal vielen dank fuer eure zahlreichen antworten! habe gestern noch ein bißchen recherchiert und bin auf codeproject , denke ich, fuendig geworden:

    http://www.codeproject.com/vcpp/stl/vector_vs_deque.asp

    leider gottes muss man des englischen maechtig sein um den artikel lesen zu koennen aber ich denke die meisten im forum werden damit kein problem haben!

    die kurzfassung: jemand wollte offenbar die unterschiede zwischen vector und deque herausfinden und hat eine testapp geschrieben und die performance dabei gemessen. der artikel ist zwar aus 2003 aber wenn sich seither nichts an der implementation von vector oder deque geaendert hat, sollte das keine rolle spielen.

    ergebniss: deque schlaegt vector beim einlesen (memory alloc) soferne vector NICHT VORHER SCHON mit reserve() eingerichtet wurde. verwendet man reserve() sind beide in etwa gleich effizient. ohne reserve: vector ~43sec deque ~27.5sec (faktor 1.5)

    das interessanteste experiment war experiment3 - "reclaiming memory". es zeigt das der zeitbedarf beim freigeben des speichers exponentiell zu wachsen beginnt je mehr elemente im deque container sind (je groesser er ist) - bei ca. 700000 strings in der testsuite brauchte deque ca. 50 sec zum freischaufeln, der vector aber nur rund 1.2 sec!!!!!!!

    ich denke ich werds mal mit vector<string> angehen, falls ich noch zeit und lust habe probier ich das ganze dann noch mit deque aus - auf jeden fall dank nochmals an alle!

    lg
    cpplumpi



  • asc schrieb:

    Mag für eine STL-Implementation stimmen, aber soviel ich weiß nicht zwangsweise für jede STL-Implementierung.

    Die meisten Implementierungen haben aber kein CoW! Wäre laut Standard möglich, macht aber so gut wie niemand. Ein wenig Statistik sollte man mit einbeziehen, und nicht vom minimalen Optimalfall ausgehen.

    asc schrieb:

    Und wenn du schon unbedingt mit Stringzeigern optimieren willst, kannst du gleich auf char* Pointer wechseln.

    👎



  • Man kann den Vector auch zuvor resizen (statt reserven) und die darin angelegten leeren Strings dann (z.B. mit getline) befüllen, schon fällt das reinkopieren weg.



  • Artchi schrieb:

    asc schrieb:

    Und wenn du schon unbedingt mit Stringzeigern optimieren willst, kannst du gleich auf char* Pointer wechseln.

    👎

    Sorry, aber ich sehe nun mal keinen Sinn darin in einen Vector in den man jeden Wert genau einmal schreibt und liest (ggf. einen vorherigen dabei überschreibt) mit einem string-Pointer (in Kombination von new/delete) zu halten wenn man sich davor schon an der string-Implementierung aufzieht.

    Und nein, ich bin absolut kein Fan von char* nur sehe ich den Sinn des stringpointers in den Zusammenhang nun wirklich nicht.

    cu André



  • huch. wo habe ich mich denn an der string-implementierung hochgezogen? ich habe nur erklärt, warum man das hier nicht mit normalen stringobjekten machen sollte.

    btw. du wolltest noch auf stl-implementierung verweisen, die implizites sharing betreiben.



  • Mag für eine STL-Implementation stimmen, aber soviel ich weiß nicht zwangsweise für jede STL-Implementierung.

    Das gilt aus einem einfachen grund für alle mir bekannten Implementierungen:

    Die einzige Möglichkeit einen std::string COW zu machen wäre wenn jeder Zugriff mit [] oder dem Dereferenzieren eines Iterators eine Kopie erzwingt (ausser natürlich wenn die String-Daten schon "exklusiv" sind).

    Das Problem ist dass der Operator [] von std::string sowie der Operator * von std::string::iterator eine Referenz (nicht const!) auf ein char zurückliefern müssen. (NOTE: es ist laut Standard nicht erlaubt anstelle des char ein Proxy-Objekt zurückzugeben)

    Und da die String Klasse nicht unterscheiden kann ob diese Referenz auch zum Schreiben verwendet wird oder nur zum Lesen müsste sie also davon ausgehen dass geschrieben wird, und an der Stelle den String kopieren.

    Die einzig mögliche COW Optimierung würde also nur dann was bringen wenn man Strings rumkopiert die nie gelesen werden, oder wenn der String zu dem Zeitpunkt wo er gelesen wird bereits der "Exklusiv-Eigentümer" der String-Daten ist.

    In diesem Fall (std::vectorstd::string vergrössern) wäre das wohl so, da das Original sofort nach dem Umkopieren des Inhaltes des std::vectorstd::string zerstört wird. Im Schnitt wird ein COW String aber vermutlich langsamer sein als ein nicht-COW String (vermutlich = ich hab's nicht ausprobiert).

    Was noch dazukommt: für kleine (kurze) Strings ist COW viel langsamer als SSO. Und SSO ist wesentlich einfacher zu implementieren.

    All das zusammengenommen bedeutet für mich (andere mögen es anders auslegen): std::string und COW vertragen sich einfach nicht gut, zumindest nicht in der Praxis 🙂

    ----

    Falls und wenn im nächsten Standard move Vektoren enthalten sind sieht die Sache wieder anders aus, aber bis dahin ist ein std::vector<boost::shared_ptrstd::string > oder ein boost::ptr_vectorstd::string die beste mir bekannte Lösung.
    (ptr_vector ist vermutlich besser, da der Overhead des shared_ptr wegfällt)

    ----

    Nochwas: ein boost::shared_ptr<std::string const> IST im Prinzip sowas wie ein manueller COW String 😉



  • asc schrieb:

    Und wenn du schon unbedingt mit Stringzeigern optimieren willst, kannst du gleich auf char* Pointer wechseln.

    Ich gehe zwar davon aus dass das nicht an mich gerichtet war, dennoch: das hatte ich als erstes vorgeschlagen 🙂

    Die anderen Vorschläge (vector + shared_ptr bzw. deque bzw. ptr_vector) hab' ich einfach gemacht weil ich *weiss* dass mit den STL Implementierungen die üblicherweise verwendet werden (MS, GCC, STLport) diese 3 sinnvolle Kandidaten sind, auf jeden Fall besser als std::vectorstd::string.

    OK, std::liststd::string ist vermutlich inetwa gleich schnell, das hatte ich übersehen/vergessen (ich brauche std::list so selten dass ich oft nicht daran denke, selbst wenn random access nicht gebraucht wird). Sei hiermit hinzugefügt.



  • hustbaer schrieb:

    Die anderen Vorschläge (vector + shared_ptr bzw. deque bzw. ptr_vector) hab' ich einfach gemacht weil ich *weiss* dass mit den STL Implementierungen die üblicherweise verwendet werden (MS, GCC, STLport) diese 3 sinnvolle Kandidaten sind, auf jeden Fall besser als std::vectorstd::string.

    Gut, habt gewonnen. Auch wenn ich mich Frage ob in diesen Anwendungsbeispiel nicht dadurch das Strings nur einmal geschrieben und ausgelesen werden müssen ein zusätzliches new/delete performancetechnisch nicht ebenso langsam ist (Werde ich vielleich irgendwann mal testen). Sofern nicht eindeutig der Flaschenhals daran hängen wird werde ich auch immer Objekte oder Smartpointer (wie von dir angegeben) rohen Zeigern vorziehen.

    Was die Implementierungen eines String angeht bin ich aber dennoch anderer Meinung. Mir ist ehrlich gesagt auch voll und ganz egal wie der String im Detail implementiert ist, ich bin und bleibe ein Anhänger des Ansatzes: Programmiere immer gegen die Schnittstelle, niemals gegen die Implementierung.

    cu André


Anmelden zum Antworten