Alternative zu tellg()
-
Hallo,
leider musste ich gerade feststellen, dass die Methode tellg() eines Filestreams auch im binary-Modus eine komplette lineare Suche von Anfang der Datei macht und deswegen extrem langsam ist. Nun habe ich allerdings eine Klasse geschrieben, die als Mischung zwischen Iterator und Stream binäre Daten von einem Filestream liest. Da mehrere Objekte dieser Klasse gleichzeitig existieren können (und sollen) muss jedes dieser Objekte sicherstellen, dass der Stream nicht in der Zwischenzeit gelesen oder versetzt wurde und gegebenenfalls seekg() aufrufen um an seine Originalposition zurückzukehren.Zur Veranschaulichung:
template<typename istream_t> class std_ibstream_iterator :public ibstream_iterator { istream_t& sequence; /*...*/ std::streampos position; /*...*/ void read_next() { //Position überprüfen und ggf. anpassen if(sequence.tellg() != position) sequence.seekg(position); //lesen collect = static_cast<typename istream_t::char_type>(sequence.get()); //aktuelle Position merken position = sequence.tellg(); /*...*/ } };Kommentiere ich alle Aufrufe von tellg() aus, läuft ein einfaches Programm mit einem einzelnen solchen Stream-Iterator wahrscheinlich 100 mal so schnell. Mit mehreren Stream-Iteratoren ginge dann aber alles drunter und drüber

Wie kann ich es vermeiden, ständig tellg() aufrufen zu müssen, selbst wenn ich sequentiell zugreife? In meinem fertigen Programm werde ich wohl nur ab und zu mal nicht-sequentiell zugreifen, allerdings wird es wohl vorkommen, dass ich mir eine Position im Stream merke und später dorthin zurückkehre.
Ich könnte natürlich die Datei mehrmals öffnen. Wäre das eine sinnvolle Alternative in punkto Geschwindigkeit und Systemressourcen?
Wäre sehr nett wenn mir jemand weiterhelfen könnte!
geloescht
-
Was hast Du für eine komische tellg-Implementierung? Also ich kann mir nicht vorstellen, dass es eine Implementierung gibt, die so etwas macht. Dafür gibt es Systemaufrufe, die in aller Regel verwendet werden.
-
Ja, die Systemaufrufe werden verwendet. Und anscheinend macht der Linux-Kernel das so, auf anderen Betriebssystemen hab ich es nicht getestet. Ich habe schon das Progrämmchen "time" verwendet und das sagt mir eindeutig, dass 90% der Zeit in Systemaufrufen vergeudet wird, solange ich tellg() so häufig verwende...

geloeschtPS: pssst, bevor hier ein Flamewar Linux vs den Rest der Welt ausbricht bitte die tellg()-Performance auf dem betreffenden System messen

-
Verbessere den Algorithmus vom Kernel und reich nen Patch ein - Fertig

-
Ich habe nicht gesagt, dass Linux einen verbesserungswürdigen Algorithmus benutzt. Tatsächlich glaube ich eher, dass meine Standardbibliothek so Dinge macht wie den filebuf leeren oder in der Datei suchen, die einfach langsame Systemaufrufe erfordern - sei es durch Festplattenzugriffe oder irgendwas anderes.
Achtung, das sind alles Vermutungen und haben mit der Lösung meines Problems nichts zu tun. Was ich wirklich suche ist eine Idee für die Implementierung meines "Stream-Iterators" ohne ständig tellg() aufrufen zu müssen, weil tellg nicht - wie ich dachte - eine Funktion ist, die zeitlich gesehen praktisch umsonst ist.
geloescht
-
Wie wärs damit:
Du postest ein minimal-Beispiel (kompilierbar) und deinen Compiler und noch dazu Compiler-Schalter zum Compilieren - dann könnte vll auch der ein oder andere sagen, dass es an der Option xyz liegt oder am Compiler oder an deinem Algo oder was auch immer...bb
-
Mach doch einen Wrapper um Deinen filestream, so dass alle Manipulationen nur über diesen Wrapper erfolgen. Der hat dann die volle Kontrolle darüber, wo sich die aktuelle Dateiposition befindet. Dann kannst Du in Deinem Fall viele tellg/seekg-Aufrufe sparen.
Also tellg macht definitiv keine lineare Suche. Dennoch ist der Aufruf eher von der langsamen Sorte, da hier ein Systemaufruf erfolgt. Systemaufrufe sind immer recht teuer. Deswegen gibt es ja die iostreams, die einen Schreib- und Lesepuffer verwalten (oder besser der verwendete streambuf, aber das ist meistens ein unwichtiges Detail), damit nicht jeder Lese- oder Schreibvorgang zu einen Systemaufruf führt.
Tellg wird zunächst sogar die Puffer leeren und dann den Systemaufruf verwenden. Er führt häufig also sogar zu mehreren Systemaufrufen. Wenn man diese vermeiden kann, ist das meistens von Vorteil.
-
@unskilled: An den Compilerschaltern liegt es definitiv nicht, da ja wie gesagt 90% der Zeit garnicht in meinem Programm verbraten wird. Teure Algorithmen habe ich noch garnicht implementiert

@tntnet: Danke, dass mit dem Wrapper ist eine gute Idee. So werde ich es wohl machen. Indem ich dem Wrapper den ausschließlichen Besitz des Streams gebe kann ich auch verhindern, dass man den Stream direkt benutzt.
geloescht