Schreiben in Ascii optimieren
-
wie mache ich das?
PC auf dem es geht Windows8wo es nicht geht:
Ubuntu 12.10
-
Eisflamme schrieb:
War das bezugnehmend auf meinen Post?
Nein, aber dein code wird trotzdem lahm sein, weil er dn ganzen locale-overhad mitnimmt.
template<typename E_in, typename Traits_in, typename E_out, typename Traits_out> void fastCopy(basic_istream<E_in, Traits_in>& in, basic_ostream<E_out, Traits_out>& out) { out << in.rdbuf(); }Was ich machen würde: datei in einn string einlsen (mittels std::stringbuf) dann den string parsen und, die Werte umwandeln, wieder in einen string umwandeln und dann als block an die Ausgabedatei anhängen.
-
Okay, aber der Witz an der Sache ist dann ja: Wie parst Du den String dann?
-
Lummel202 schrieb:
wie mache ich das?
PC auf dem es geht Windows8wo es nicht geht:
Ubuntu 12.10Hänge einfach ein .c_str() hinten an.
-
void evenFasterCopy(std::string cconst& inPath, std::string const& outPath) { boost::iostreams::mapped_file_source in(inPath); boost::iostreams::mapped_file_sink out(outPath, in.size()); if(!in.is_open() || !out.is_open()) return; std::memcpy(out.data(), in.data(), in.size()); }Wenn ich nichts übersehen habe.
-
Eisflamme schrieb:
Okay, aber der Witz an der Sache ist dann ja: Wie parst Du den String dann?
da gibts so einige Möglichkeiten. Die 3-Zeilen Lösung wäre in diesem Fall spirit::qi. Hab ich gemacht, top performance, bin hoch zufrieden.
-
Hi,
Ethon:
Und wie willst Du das jetzt zu einem Parser erweitern?Also ich habe das Mal kurz weitergebaut. Der jetzige Parser liest den ersten double, führt die Konvertierungsfunktion aus, gibt den konvertierten Wert aus und schreibt den Rest der Zeile in die Datei (wobei er ' ' durch '\t' ersetzt).
Ich muss zugeben, das Parsen und Schreiben vom double ist das Bottleneck (wäre es das nicht aber sowieso immer?). 140 MB konvertieren bei mir jedenfalls in 18 Sekunden, wobei man dazu sagen muss, dass meine Festplatte gerade auch ordentlich zu tun hat. Weiß nicht, wie sehr das Auswirkungen hat. Rechnet man das gemäß Werners Annahme hoch, dürfte das ganze Prozedere also ungefähr 2 Minuten dauern.
Findest Du das lahm, otze? Wie schnell könnte man mit einem "richtigen Parser" denn werden?
#include <iostream> #include <sstream> #include <fstream> #include <ctime> #include <iterator> using namespace std; const double t_offset12 = 0.12; const double t_offset13 = 0.13; const double t_offset14 = 0.14; const double t_offset15 = 0.15; // whatever offsets are double getTimeStamp(double a, unsigned int fileNumber) { double timestamp; if(fileNumber / 8 < 1) timestamp = a; if(fileNumber / 8 < 2 && fileNumber / 8 > 0.99) timestamp = a + t_offset12; if(fileNumber / 8 < 3 && fileNumber / 8 > 1.99) timestamp = a + t_offset13; if(fileNumber / 8 < 4 && fileNumber / 8 > 2.99) timestamp = a + t_offset14; if(fileNumber / 8 < 5 && fileNumber / 8 > 3.99) timestamp = a + t_offset15; if(fileNumber / 8 < 6 && fileNumber / 8 > 4.99) timestamp = a + t_offset12; else timestamp = 0.; return timestamp; } template<typename E_in, typename Traits_in, typename E_out, typename Traits_out> void parse(basic_istream<E_in, Traits_in>& in, basic_ostream<E_out, Traits_out>& out, unsigned int fileNumber) { typedef basic_istream<E_in, Traits_in> istream_t; typedef basic_ostream<E_out, Traits_out> ostream_t; istream_t::sentry ok_in(in); ostream_t::sentry ok_out(out); if(ok_in && ok_out) { ios_base::iostate state_in = ios_base::goodbit; ios_base::iostate state_out = ios_base::goodbit; try { typedef istream_t::_Iter in_it; typedef num_get<E_in, in_it> numget; typedef ostream_t::_Iter out_it; typedef num_put<E_out, out_it> numput; const numget& getter = use_facet<numget>(in.getloc()); const numput& putter = use_facet<numput>(out.getloc()); for(;;) { // read double and write it double d; getter.get(in_it(in.rdbuf()), in_it(0), in, state_in, d); putter.put(out_it(out.rdbuf()), out, out.fill(), getTimeStamp(d, fileNumber)); // copy rest of line while converting ' ' to '\t' Traits_in::int_type m; char c; while(!Traits_in::eq_int_type(m = in.rdbuf()->sbumpc(), Traits_in::eof())) { c = Traits_in::to_char_type(m); if(c == ' ') c = '\t'; out.rdbuf()->sputc(c); if(m == '\n') break; } if(Traits_in::eq_int_type(m, Traits_in::eof())) break; } } catch(...) // unschön, aber ich konnte nicht feststellen, dass sbumpc() nicht throwen kann { state_in |= ios_base::badbit; if(in.exceptions() & ios_base::badbit) throw; state_out |= ios_base::badbit; if(out.exceptions() & ios_base::badbit) throw; } in.setstate(state_in); out.setstate(state_out); } } // =================================================== int main() { time_t start = time(0); { ifstream ifs("C:/someInput.txt", ios::binary); ofstream ofs("C:/someOutput.txt", ios::binary); ofs.precision(15); parse(ifs, ofs, 1); cout << "Time difference: " << difftime(time(0), start) << " seconds"; } int x; cin >> x; }Edit XY:
Und "\t\t", i am Zeilenende fehlen natürlich noch...
-
Kein Kommentar? Gerne auch Kritik von Werner (geht das so in Ordnung oder habe ich irgendwas vergessen? Vermutlich müsste ich noch die States wenigstens einmal pro Schleife oder so prüfen?), eine bessere non-stream-Lösung oder eine Rückmeldung von OP, ob er das weiterbauen kann.

-
Hab gerade selber nicht viel Zeit. Abeer du kannst ja mal nen spirit parser dagegen anlaufen lassen.
-
Ethon:
Und wie willst Du das jetzt zu einem Parser erweitern?Die anderen Copy-Vorschläge hier hatten auch nicht viel mit Parsern zu tun.
Aber: Ich würde einen Streambuf schreiben der auf den Memory-Mapped files operiert (bzw ich gehe stark davon aus dass es den in Boost scchon gibt, scchließlich sind die MemorymappedFiles ein Teil von Boost.Iostreams).Damit spart man sich einiges an Rumkopiererei im Speicher und überlässt dem OS die Entscheidung, was jetzt im Speicher liegt oder auf der Platte bleibt.
-
Hallo Lummel,
vor einiger Zeit bin ich auf diese Diskussion gestoßen und fand das Ergebnis ganz interessant. Das zweite Beispiel ist zwar nicht mehr C++, schau dir aber noch den Rest an. Du hast hier schon einige gute Vorschläge bekommen, aber vielleicht hilft's dir weiter.
-
Werner Salomon schrieb:
Hallo Eisflamme,
Eisflamme schrieb:
Werner:
Wäre hier nicht wieder ein guter Trick statt operator>> eine eigene Version zu schreiben, die nur ein einzelnes sentry-Objekt pro Lesevorgang aus der Datei erzeugt? In deiner Version hast Du ja auch ein sentry pro Zeile. Könnte man nicht sogar eine Funktion schreiben, die gleichzeitig für Output und Input ein sentry erzeugt und die Zeichen dann gar nicht zwischenspeichert, sondern den sget() direkt sput()ted?Vielleicht ist das für OP zu viel und es geht hier auch nicht um meine Frage, aber in die Richtung hätte ich jetzt gedacht.
Ich weiß schon auf welchen Thread Du Bezug nimmst. Na ja - mach' Du mal, ich gehe jetzt in's Bett.
Ansonsten - beachte den Kommentar zu meinem eigenen Beitrag.
Gutes Nächtle
WernerWas ich ziemlich interessant fand: http://www.soi.ch/phpBB3/viewtopic.php?p=2120#p2120
Es ist nicht nur das Sentry, was langsam ist, sondern der ganze Parser der Streams.