file write mit high performance



  • Hi,

    wie kann ich am effektivsten logging bloecke in ein file schreiben?
    file.write oder mit streams:

    bool write(std::string::const_iterator begin, unsigned int size) {
            copy_n(begin, size, ostream_iterator<char>(file_));
            //....
    }
    

    mit bloecke meine ich das die bloecke mit log informations unterschiedliche groesse haben und mit einem delimiter getrennt sind... x bytes bis 32mb...


  • Mod

    ostream_iterator benutzt den operator<< zur Ausgabe, also eine formatierte Ausgabefunktion. Das heißt, das Ergebnis ist nicht unbedingt identisch zu write (und ostream_iterator ist langsamer, möglicherweise sogar deutlich). Falls du einen ostreambuf_iterator benutzen würdest, sollte deine Funktion so ziemlich identisch sein zu dem, was ostream::write macht (sowohl vom Ergebnis her als auch zu dem, was intern passiert). Das bedeutet natürlich, dass du auch gleich ostream::write benutzen kannst, falls dies das richtige für dich ist. ostreambuf_iterator und write sind halt beide unformatiert, ob das richtig ist oder nicht, musst du selber wissen.

    Das copy mag ich in keinem Fall, es wird bestenfalls genau so gut sein wie die Funktionen, die du damit emulierst. Beim ostreambuf_iterator ist es, wie erklärt, quasi identisch zu write. Bei ostream_iterator ist es quasi identisch zu operator<<(string), sofern die Größe den gesamten String umfasst. Tut sie das denn nicht?

    Jedenfalls ist die Entscheidung wohl vor allem, ob du formatiertes Schreiben möchtest oder nicht (vermutlich reicht dir unformatiert, außer du hast sehr spezielle Erwartungen). Es ist wie die Entscheidung zwischen operator<< und ostream::put was die Ausgabe von char angeht.



  • Hi SeppJ,

    danke fuer die info.

    Es ist wie die Entscheidung zwischen operator<< und ostream::put was die Ausgabe von char angeht.

    ... und mit ofstream::write?

    wie kann ich am effektivsten n bytes am anfang eines files loeschen?

    LG



  • mark123 schrieb:

    wie kann ich am effektivsten n bytes am anfang eines files loeschen?

    Das geht nicht. Du kannst nur drüberschreiben.



  • geht nicht?

    sowas in der art wuerde gehn, kann mir jemand tipps geben bzgl. performance optimierung?

    void remove_first_n(const unsigned int &file_id, const unsigned int &n) {
          std::string filename = build_file_name(file_id);
          std::string temp(std::tmpnam(0));
          std::ifstream in(filename.c_str());
          std::ofstream out(temp.c_str());
          unsigned int size = get_file_size(file_id);
    
          if (n) {
            unsigned int new_size = size - n;
            in.clear();
            in.seekg(n);
    
            for (int i = 0; i < new_size; ++i) {
              out.put(in.get());
            }
    
            in.clear();
            in.close();
            out.close();
            std::remove(filename.c_str());
            std::rename(temp.c_str(), filename.c_str());
          }
        }
    


  • Verwende besser nicht put/get, sondern lese und schreibe in Chunks. Intern werden zwar Buffer verwendet, aber jeh nachdem wir groß die Datei ist machst du doch zu viele Systemaufrufe.



  • mark123 schrieb:

    geht nicht?

    Ja, geht nicht.
    Was du zeigst ist ja nicht Bytes am Anfang Löschen sondern ein neues File erzeugen, Daten rüberkopieren usw.
    Hat wenn es ungestört durchläuft zwar den selben Effekt, ist aber grundsätzlich schon was anderes.

    mark123 schrieb:

    sowas in der art wuerde gehn, kann mir jemand tipps geben bzgl. performance optimierung?

    Ja: Grössere Blöcke kopieren statt immer 1 Byte. Sagen wir mal so ca. 1~10 MB.
    Dass das File dabei komplett umkopiert werden muss kannst du aber nicht verhindern, d.h. schneller als die HDD/SSD/... wirst du dabei niemals werden.



  • hier die aufgabe die ich gerade baue: http://ideone.com/4Y5uRE

    @hustbaer: ich habe jetzt am anfang jeden files einen offset. dh wenn ich gerade in dem file einen record am anfang raus loeschen muss dann setzt ich den offset entsprechend und muss das file nicht umkopieren...

    welcher code laeuft schneller?

    1.)
    int bytes_written = write(data, bytes_to_write);
    
    bool write(std::string::const_iterator begin, unsigned int size) {
            copy_n(begin, size, ostream_iterator<char>(file_));
    }
    
    2.)
    int bytes_written = write(data, write_index, bytes_to_write);
    
    bool write(std::string &begin, unsigned int write_index, unsigned int size) {
            file_.write(begin.c_str()+write_index, size);
    }
    


  • @hustbaer:
    - im moment werden die records ueber mehrere files verteilt...alle files haben die gleiche groesse...
    - am anfang des files habe ich einen keinen header (wo der file offset steht)
    - wenn ich x records am anfang loeschen muss dann berechne ich die files die ich komplett loeschen kann, bei einem file indem ein andere record gespeichert ist setze ich einfach den offset im file header entsprechend.

    die frage: soll ich 1 record per file speichern oder mehrere records pro file?
    wenn ich 1 record per file haette waere es zum implemtieren einfacher, jedoch die files waeren unterschiedlich gross...nachteil/vorteil?


  • Mod

    mark123 schrieb:

    nachteil/vorteil?

    Das musst du selbst beurteilen, wir kennen schließlich deine Anforderungen nicht.

    welcher code laeuft schneller?

    Probier's doch aus. Außerdem habe ich den Unterschied doch schon erklärt.



  • @SeppJ: anforderungen sind hier: http://ideone.com/4Y5uRE

    bitte um feedback...



  • ping um feedback...



  • mark123 schrieb:

    @SeppJ: anforderungen sind hier: http://ideone.com/4Y5uRE
    bitte um feedback...

    Für 4500€ erledige ich das.



  • Mach doch einfach selbst einen Performance Test. Einfach deine Funktionen mehrfach hinter einander aufrufen, jeweils die Zeit stoppen und den Mittelwert berechnen und das selbe dann mit der anderen Funktion.

    Oder eben anhand der Angaben von Sepp einfach mal selber darüber nachdenken, dann vergisst du es auch so schnell nicht mehr.

    MFG Marco


  • Mod

    Oder besser: Gar nicht darüber nachdenken. Ich bin angesichts der Aufgabenstellung entsetzt (aber nicht verwundert), dass er sich über diese Sache Gedanken macht. Geht völlig am Ziel vorbei.



  • @volkard: ich moechte es selber machen, bzw. habe es schon...

    @SeppJ: warum am ziel vorbei? stell dir vor es werden viele kleine blobs erstellt 100k, das waeren dann 100k files (bei einen 1 blob per file approach)... und wenn ich alle blobs ausgeben moechte, dann muss ich 100k files oeffnen und lesen...
    bleibt mir nicht uebrig als beide versionen zu implementieren und performance zu messen....?



  • mark123 schrieb:

    und wenn ich alle blobs ausgeben moechte, dann muss ich 100k files oeffnen und lesen...

    Mhhm. Mal 40000 Files mit durchschnittlich 7000 Bytes anschauen…

    # time grep -r foo /usr/src/linux --include=".c" --include=".h"
    real 0m30.764s //USB-Stick
    user 0m1.181s
    sys 0m1.195s
    # time grep -r foo /usr/src/linux --include=".c" --include=".h"
    real 0m0.617s
    user 0m0.483s
    sys 0m0.126s

    Tut also nicht weh. Und damits auf Windows95 oder OS/400 auch schnell ist, kannste ja zum Bleistift Blobs zusammenfassen in Dateien, solange die Datei kleiner als 32M ist. Ich würde vielleicht eine feste Dateigröße nehmen. Sagen wie mal 2^20 und die vorderen Bits meiner 64-Bit-"Zeiger" bildeten die Dateinamen und die hinteren die Dateioffsets. Zahlenüberlauf eingeplant.
    "Truncation must be efficient and not require too much copying of data" Jo, wir requiren no copy of data.
    "Disk space used must remain roughly proportional to retained data size." Jo, plus 2M Fixkosten. Gefällt mir besser als bis zu 1M Kopierkosten pro Aufräumlauf.
    Also fast genau, was Du im Moment hast, ich würde die Header nicht in den Files halten, sondern in einem anderen File, fürchte ich. Obwohl, dann wirds ja wieder langsamer. Header fester Größe geht ja auch. Nee, unnötig, die Extradatei hat feste Größe, braucht ja bloß Anfangszeiger und Endezeiger zu kennen und was in der Aufgabenstellung "position" heißt, ist auch ein 64-Bit-"Zeiger".


  • Mod

    mark123 schrieb:

    @SeppJ: warum am ziel vorbei?

    Weil es nicht das Ziel der Aufgabe ist. So einfach kann die Antwort sein.

    Falls du die eigentliche Aufgabe noch nicht gelöst haben solltest, weil du dich mit Nebenzielen dieser Art aufhältst, hast du übrigens ein Problem. Die ist nämlich durchaus umfangreich und anspruchsvoll.


Log in to reply