1,000,000 floats einlesen
-
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
-
und wenn dein rechner jetzt einfach 5x schneller ist als seiner? deshalb auch die cpp version zum vergleich.
-
Die 2. C# Variante ist wirklich in etwa doppelt so schnell, also ~450 ms.
(In etwa so schnell wie fread+strtod.)
-
camper schrieb:
// Spirit-Lösung
2610 ms ... allerdings ist irgendein Fehler drin, jedenfalls wird nicht alles richtig geparst. In jedem Falle ist es viel zu langsam.
Hm, hatte auch so ähnliche Zeiten gestern Abend, kam dann aber nicht mehr dazu, weiter zu testen. Ich denke aber, es liegt daran, dass der Iterator successive die gesamte Datei puffert. Wenn du gerade Gelegenheit hast, probiere mal die Parsergrammatik
*(float_ >> boost::spirit::repository::flush_multi_pass)
. Damit wird nach jedem eingelesenen float der Buffer gelöscht. Das flush_multi_pass findet man inboost/spirit/repository/include/qi_flush_multi_pass.hpp
.
Schneller, als vorher die gesamte Datei in einenvector
zu laden, wird es aber vermutlich nicht sein.
-
cooky451 schrieb:
Die 2. C# Variante ist wirklich in etwa doppelt so schnell, also ~450 ms.
(In etwa so schnell wie fread+strtod.)Also nehmt euch ein Beispiel am 2. Quellcode
-
ipsec schrieb:
camper schrieb:
// Spirit-Lösung
2610 ms ... allerdings ist irgendein Fehler drin, jedenfalls wird nicht alles richtig geparst. In jedem Falle ist es viel zu langsam.
Hm, hatte auch so ähnliche Zeiten gestern Abend, kam dann aber nicht mehr dazu, weiter zu testen. Ich denke aber, es liegt daran, dass der Iterator successive die gesamte Datei puffert. Wenn du gerade Gelegenheit hast, probiere mal die Parsergrammatik
*(float_ >> boost::spirit::repository::flush_multi_pass)
. Damit wird nach jedem eingelesenen float der Buffer gelöscht. Das flush_multi_pass findet man inboost/spirit/repository/include/qi_flush_multi_pass.hpp
.
Schneller, als vorher die gesamte Datei in einenvector
zu laden, wird es aber vermutlich nicht sein.2630 ms, also keine Verbesserung. Der Bug ist immer noch drin, die ersten 4542 Zahlen korrekt eingelesen, danach gibt es Abweichungen. Allerdings habe ich nicht die Zeit zum debuggen. Der Programmcode ist ja simpel genug, also vermutlich korrekt. Bleibt die Möglichkeit, dass die Biblithek ein Problem hat oder der Compiler fehlerhaften Code erzeugt.
-
#include <ctime> #include <fstream> #include <iostream> int main() { std::ifstream input(".\\test.txt"); // create copy of current global locale std::locale loc; // iterator to read from standard input typedef std::istreambuf_iterator<char> InIt; InIt beg = InIt(input); InIt end = InIt(); // stream which defines input format std::ios_base& fmt = input; // declare output arguments std::ios_base::iostate err = std::ios::goodbit; // get numeric input facet of the locale loc std::num_get<char, InIt> const& ng = std::use_facet<std::num_get<char, InIt> >(loc); float* data = new float[1000000]; clock_t startClock = std::clock(); for(int i = 0; (i < 1000000) && (err == std::ios::goodbit); ++i) { ng.get(beg, end, fmt, err, data[i]); ++beg; } clock_t endClock = std::clock(); double duration = endClock - startClock; duration /= CLOCKS_PER_SEC; std::cout << duration << std::endl; delete[] data; return 0; }
strtod / fscanf / stream / streambuffer ~ 0.47 / 1 / 1.4 / 0.94
Anregung aus
http://www.josuttis.com/libbook/i18n/numget.cpp.htmlGruß