1,000,000 floats einlesen
-
VS 2010:
C - fread + strtod: ~90 ms
C - fscanf: ~160 ms
C++ - ifstream: <15 ms (nicht mehr messbar)GCC 4.4.1 (TDM):
C - fread + strtod: ~1020 ms (<- wtf?)
C - fscanf: ~210 ms
C++ - ifstream: ~85 msC++ führt auf meiner Maschine noch immer mit Abstand und ich muss sagen, die Ergebnisse überraschen mich auch. Einen so signifikanten Vorsprung durch C++ hätte ich nicht erwartet.
Noch nicht abgeklärte Unterschiede:
- Festplatte? (Hab eine ältere SSD)
- Wie sieht dietest.txt
Datei aus? Ich habe einfach durch Leerzeichen getrenntefloat
Zahlen per Random reingeschrieben.Grüssli
-
Komisch, ich kann cookie451s Ergebnisse bestätigen. Compiliert mit GCC 4.4.3. Wobei bei mir der ifstream nicht so total eingeht, das Verhältnis ist eher 3:2.5:1.5. Ich habe auch mal versucht die while-Schleife durch eine for-Schleife zu ersetzen (wir wollen ja fair sein - beim C code wird nie geprüft ob das Lesen erfolgreich war), aber das machte 0 Unterschied.
Maschine ist ein i7 mit einem RAID1 Festplattenverbund. Datei enthielt 1 Million floats zwischen 0 und 1 durch \n getrennt. Wobei die Datei aber vollständig im RAM lag, aufgrund des Caches.
-
ca: 500ms:500ms:2000ms mit gcc 4.5.2 auf einem atom 330
Die Zeiten hängen auch vom Wertebereich ab, die Relation is aber immer ungefähr 1:1:4
-
Habe noch ein bisschen mit dem Code rumgespielt, und eine spirit-Variante hinzugefügt (Version 4):
#include <boost/spirit/include/qi.hpp> #include <iostream> #include <string> #include <vector> #include <ctime> #include <fstream> #include <iostream> static const char *g_fileName = "test.txt"; static const int g_floatCount = 1000000; int main() { using namespace std; time_t t1; t1 = clock(); ifstream is(g_fileName); cout << "Time to open: " << clock() - t1 << "ns\n"; vector<float> buf; buf.reserve(g_floatCount); t1 = clock(); int i = 0; string s; while ( getline( is, s ) ) { namespace sp = boost::spirit; sp::qi::phrase_parse(s.begin(), s.end(), *sp::qi::float_ , sp::ascii::space, buf); }; cout << "Time to parse: " << clock() - t1 << "ns\n"; t1 = clock(); is.close(); cout << "Time to close: " << clock() - t1 << "ns\n"; cin >> i; cout << buf[i] << endl; return 0; }
510ms:1080ms:1830ms:570ms
-
ich hab's auch mal probiert. Meine Ergebnisse sind
Visual Studio 2008 Express Edition, Release
C - fread + strtod: geht gar nicht!! die Schleife mit strtod endet nicht
C - fscanf: ~690 ms
C++ - istream: ~1510 ms
C++ - boost.spirit: ~790msund die 5. Variante, ist wie C++ mit istream, aber eigener num_get-facette für Float
C++ - ifstream + eigenes num_get-Float: ~610ms// liest float ohne(!) Vorzeichen nur in Gleitkommadarstellung (kein Exponent); keine Überlaufprüfung class GetFloat : public std::num_get< char > { protected: typedef std::istreambuf_iterator< char > iterator_type; virtual iterator_type do_get( iterator_type first, iterator_type last, std::ios_base& /*iosbase*/, std::ios_base::iostate& state, float& val ) const { // get float from [first, last) into val bool ok = false; val = 0.f; float divisor = 1.f; for( bool vorkomma = true; first != last; ++first ) { if( *first == '.' && vorkomma ) { vorkomma = false; continue; } if( *first < '0' || *first > '9' ) break; ok = true; (val *= 10.f) += float(*first - char('0')); if( !vorkomma ) divisor *= 10; } val /= divisor; if ( !ok ) state |= std::ios_base::failbit; if( first == last ) state |= std::ios_base::eofbit; return first; } };
Einzufügen in 'C++ - ifstream' hinter Zeile 15
is.imbue( locale( is.getloc(), new GetFloat ) );
Gruß
Werner
-
Ich habe jetzt bisher nur mal ifstream probiert: Habe in die Datei eine Millionen floats schreiben lassen von 0.1234 bis 999999.1234. Was ich bemerkt habe ist folgendes: Wenn ich in jede Zeile, einen Wert schreibe, dann bin ich bei ~1700ms, schreibe ich dir Werte jedoch fortfolgend hintereinander, benötigt er nur ~330 ms.
Würd jetzt ja auch noch kurz die anderen Varianten prüfen, das muss aber bis morgen warten, denn ich schreibe morgen eine Mathe-Klausur und das geht jetzt natürlich vor
Lg freeG
-
Bei so komischen Werten habe ich mir mal die Mühe gemacht 3 Versionen (statisch gelinkt) zu bauen und mit den test.txt Dateien hochzuladen. (Einmal mit Zeilen, einmal mit Leerzeichen getrennt)
http://www20.zippyshare.com/v/88004697/file.html (VS 2010)
Es ist doch irgendwie unwahrscheinlich, dass der gleiche Code auf verschiedenen Rechnern so unterschiedlich "gut" läuft. Jetzt bin ich ja mal gespannt
(Meine Testergebnisse ändern sich kaum, sind auch mit beiden .txt Dateien fast gleich)
Werner Salomon schrieb:
C - fread + strtod: geht gar nicht!! die Schleife mit strtod endet nicht
Kannst du das Problem mal näher beschreiben? Ich kann mir nicht so recht vorstellen warum die Schleife nicht enden sollte
Edit:
Hab das Ganze auch gleich mal auf meinen Netbook getestet. (Atom 1.8GH)
fread+strtod: ~1555ms
fscanf: ~3200ms
ifstream: ~4750msHat sich also nicht wirklich viel geändert..
Edit:
Dravere schrieb:
C++ - ifstream: <15 ms (nicht mehr messbar)
Bist du dir sicher, dass in deiner Datei kein #INF steht? Dann wäre die C++ Variante nämlich die einzige die abbrechen würde. <15ms scheint dann doch irgendwie unrealistisch zu sein
-
So folgende Werte hab ich nun:
test.txt
fread-strtod: ~620ms
fscanf : ~1300ms
ifstream : ~1830test2.txt
fread-strtod: ~620ms
fscanf : ~1290ms
ifstream : ~1820msSo nun verhält es sich bei mir zwischen beiden Text-Dateien gleich.
Bei meiner Version war jedoch ifstream mit der Datei wie deine test2.txt wesentlich schneller. Warum weiß ich leider auch nicht.Lg freeG
-
Habe die spirit-Version angepasst, so dass sie wie Version1 erst einmal das ganze File einliest:
#include <boost/spirit/include/qi.hpp> #include <iostream> #include <vector> #include <ctime> #include <fstream> #include <iostream> #include <algorithm> #include <iterator> static const char *g_fileName = "test.txt"; static const int g_floatCount = 1000000; int main() { using namespace std; time_t t = clock(); ifstream is(g_fileName, ios_base::binary ); is.seekg(0, std::ios_base::beg); ifstream::pos_type len = is.tellg(); is.seekg(0, std::ios_base::end); len = is.tellg() - len; is.seekg(0, std::ios_base::beg); vector<char> input(len); is.read( &input.front(), len ); cout << "Time to open&read: " << clock() - t << '\n'; t = clock(); vector<float> buf; buf.reserve(g_floatCount); namespace sp = boost::spirit; sp::qi::phrase_parse(&input[0], &input[0]+input.size(), *sp::qi::float_ , sp::ascii::space, buf); cout << "Time to parse: " << clock() - t << '\n'; int i = 0; cin >> i; cout << buf[i] << endl; return 0; }
Zeiten (jeweils lesen+parsen) für test.txt:
Version 1 (fread-strtod) : 710 ms
Version 2 (fscanf): 1270 ms
Version 3 (ifstream): 1910 ms
Version 4 (ifstream+spirit): 590 mstest2.txt:
Version 1 (fread-strtod) : 690 ms
Version 2 (fscanf): 1280 ms
Version 3 (ifstream): 1900 ms
Version 4 (ifstream+spirit): 580 ms
-
Möchte jemand Spirit nochmal in Verbindung mit dem Multi Pass Iterator testen?
In Kürze: Den
istream_iterator
ausboost/spirit/include/support_istream_iterator.hpp
benutzen (das ist ein buffernder Iterator, damit ist er ein ForwardIterator und kein InputIterator, Spirit kann somit damit arbeiten).Damit müsste man weder das komplette File laden, noch ein teures
getline
machen und hätte immer noch (denke ich) sehr gute Geschwindigkeit.
-
camper schrieb:
Zeiten (jeweils lesen+parsen) für test.txt:
Version 1 (fread-strtod) : 710 ms
Version 2 (fscanf): 1270 ms
Version 3 (ifstream): 1910 ms
Version 4 (ifstream+spirit): 590 mstest2.txt:
Version 1 (fread-strtod) : 690 ms
Version 2 (fscanf): 1280 ms
Version 3 (ifstream): 1900 ms
Version 4 (ifstream+spirit): 580 msDass boost::spirit so gut abschneidet, hätte ich nie gedacht. Erstaunlich!
-
Aus Spaß an der Freude hab ich das auch mal mit C# .NET gemacht. Wenn ich keinen Perfomancefehler gemacht habe, komme ich auf 1,7 Sekunden. Vielleicht intressiert es jemanden
-
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/support_istream_iterator.hpp> #include <iostream> #include <vector> #include <ctime> #include <fstream> #include <iostream> #include <algorithm> #include <iterator> static const char *g_fileName = "test.txt"; static const int g_floatCount = 1000000; int main() { using namespace std; ifstream is(g_fileName); vector<float> buf; buf.reserve(g_floatCount); time_t t = clock(); namespace sp = boost::spirit; sp::qi::phrase_parse( sp::istream_iterator(is), sp::istream_iterator(), *sp::qi::float_, sp::ascii::space, buf ); cout << "Time to parse: " << clock() - t << '\n'; int i = 0; cin >> i; cout << buf[i] << endl; return 0; }
2610 ms ... allerdings ist irgendein Fehler drin, jedenfalls wird nicht alles richtig geparst. In jedem Falle ist es viel zu langsam.
-
FreakY<3Cpp schrieb:
Aus Spaß an der Freude hab ich das auch mal mit C# .NET gemacht. Wenn ich keinen Perfomancefehler gemacht habe, komme ich auf 1,7 Sekunden. Vielleicht intressiert es jemanden
Um die Werte zu vergleichen müsstest du jetzt schon den Code posten, sonst ist das zu CPU abhängig
So.. mit gleichen .txt's scheinen die Werte ja alle übereinzustimmen. (Nebenbei bemekert boost::spirit ist wohl echt erstaunlich gut :D)
Bleibt die Frage, warum die C++ filestreams so viel langsamer sind? Hat jemand da eine gut Erklärung für? Dass floats da auch ein Komma als Trennzeichen haben können, scheint mir irgendwie keine ausreichende Erklärung für den immensen Zeitverlust zu sein..
-
cooky451 schrieb:
FreakY<3Cpp schrieb:
Aus Spaß an der Freude hab ich das auch mal mit C# .NET gemacht. Wenn ich keinen Perfomancefehler gemacht habe, komme ich auf 1,7 Sekunden. Vielleicht intressiert es jemanden
Um die Werte zu vergleichen müsstest du jetzt schon den Code posten, sonst ist das zu CPU abhängig
static void Main(string[] args) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); string[] array; using (StreamReader sr = new StreamReader("Floats.txt")) { double result; //floats auslesen und formatexception "abfangen" array = sr.ReadToEnd().Split('\n').Where(s => double.TryParse(s, out result)).ToArray(); } List<float> l = new List<float>(); //string to float konvertierung foreach (string s in array) { l.Add((float)Convert.ToDouble(s)); } sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); Console.ReadKey(); } /* für diejenigen die auf Extensions und Einzeiler stehen :P using (StreamReader sr = new StreamReader("Floats.txt")) { double result; List<float> list = sr.ReadToEnd().Split('\n').Where(s => double.TryParse(s, out result)).ToList() .ConvertAll(new Converter<string, float>(s => (float)Convert.ToDouble(s))); } */
-
Danke.
C# braucht bei mir gerade mal ~950 msEdit:
Ist also in etwa so schnell wie fscanf, hätte ich nicht gedacht.
-
cooky451 schrieb:
Danke.
C# braucht bei mir gerade mal ~950 msEdit:
Ist also in etwa so schnell wie fscanf, hätte ich nicht gedacht.Ja bei mir dauerts ein bisschen länger. Hab eine etwas lahme Krücke als PC, aber ich bin zufrieden :p
-
Ich kriegs auf 375ms
static void Main(params string[] args) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); List<float> l = new List<float>(); using (StreamReader sr = new StreamReader("Floats.txt")) { float result; while (!sr.EndOfStream) { if(float.TryParse(sr.ReadLine(), out result)) l.Add(result); } } sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds+"ms"); Console.ReadKey(); }
-
Firefighter schrieb:
Ich kriegs auf 375ms
Du musst natürlich auch die C++-Varianten ausführen und deren Zeiten posten. Absolut hat das sonst keinen Wert.
-
Ich bezog mich ja gerade auf die Vorherige Variante von FreakY<3Cpp