Schnelles lesen von großen Dateien in den Speicher



  • vector<char> buffer(length,0);
    infile_N.read(&buffer[0],length);
    

    Ist nicht besonders vorteilhaft, wenn es dir darum geht, dass du schnell lesen willst.

    std::vector<char> buffer;
    buffer.reserve(length);
    

    Ist sicher besser.


  • Mod

    Mentras schrieb:

    vector<char> buffer(length,0);
    infile_N.read(&buffer[0],length);
    

    Ist nicht besonders vorteilhaft, wenn es dir darum geht, dass du schnell lesen willst.

    std::vector<char> buffer;
    buffer.reserve(length);
    

    Ist sicher besser.

    Nicht nur unnötig, sondern auch falsch. Und die erste Variante sollte unter dem schnellsten sein, was geht.

    edit: Und an den Threadersteller: Eine Datei in einen Stringstream lesaen geht auch ohne Umwege:

    stringstream parser;
    ifstream fiel;
    file >> parser;
    


  • SeppJ schrieb:

    Nicht nur unnötig, sondern auch falsch. Und die erste Variante sollte unter dem schnellsten sein, was geht.

    Dann scheine ich die Dokumentation nicht zu verstehen.

    Der Konstruktoraufruf vegrößert den vector um length Bytes und initialisiert jedes Element mit 0 (Auf sein Beispiel bezogen). Also das Äquivalent zu .resize() Methode.

    Deswegen dachte ich mir:

    Einen riesen großen vector (1500001881 Bytes) mit Nullen zu initialisieren ist sicher langsamer als bloß den Speicher dafür zu reservieren.


  • Mod

    Mentras schrieb:

    SeppJ schrieb:

    😮 Was? 😕 😕 😕

    Einen riesen großen vector (1500001881 Bytes) mit Nullen zu initialisieren ist sicher langsamer als bloß den Speicher dafür zu reservieren.

    Und wenn du dann drauf zugreifst, kracht es.



  • SeppJ schrieb:

    Und wenn du dann drauf zugreifst, kracht es.

    Stimmt. Daran habe ich nicht gedacht.
    Danke!



  • Mentras schrieb:

    SeppJ schrieb:

    Und wenn du dann drauf zugreifst, kracht es.

    Verstehe ich nicht, könntest du es mir bitte erklären? 😮

    Mit std::vector<..>::reserve(..) wird nur der Speicher reserviert, d.h. std::vector<..>::capacity() verändert, nicht aber std::vector<..>::size().



  • SeppJ schrieb:

    stringstream parser;
    ifstream fiel;
    file >> parser;
    

    Das habe ich als erstes ausprobiert, funktioniert so leider nicht.



  • wm schrieb:

    SeppJ schrieb:

    stringstream parser;
    ifstream fiel;
    file >> parser;
    

    Das habe ich als erstes ausprobiert, funktioniert so leider nicht.

    Nein wie doof es geht exakt andersherum.

    std::stringstream << std::ifstream
    


  • Geht das ganze auch irgendwie ASCII? Irgendwie bekomme ich nur "0040F7D0"


  • Mod

    wm schrieb:

    Geht das ganze auch irgendwie ASCII? Irgendwie bekomme ich nur "0040F7D0"

    Was genau? Stell die Frage mal so, dass man nicht den kompletten Thread lesen muss, um sie zu verstehen.



  • Kurze Frage: Ist die Anzahl der Werte je Zeile immer gleich?



  • Tachyon schrieb:

    Kurze Frage: Ist die Anzahl der Werte je Zeile immer gleich?

    Ich habe verschiedene Dateien mit Matrizen unterschiedlicher Größe. Je Datei sind bleibt die Größe konstant.

    SeppJ schrieb:

    Stell die Frage mal so, dass man nicht den kompletten Thread lesen muss, um sie zu verstehen.

    mit localStream << inFile_N;
    
    while( getline( localStream , line ) )
    {
    

    kann ich getline nutzen aber die ausgelesenen Werte scheinen nicht ascii codiert zu sein.

    "0027F728ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ"
    "0027F728ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ"
    

    Wenn ich aber:

    vector<char> buffer(length,0);
    infile_N.read(&buffer[0],length);
    
    std::stringstream localStream;
    localStream.rdbuf()->pubsetbuf(&buffer[0],length);
    
    while( getline( localStream , line ) )
    {
    

    benutze dann ist der Inhalt richtig aber getline bringt immer wieder einen leeren string.



  • wm schrieb:

    Tachyon schrieb:

    Kurze Frage: Ist die Anzahl der Werte je Zeile immer gleich?

    Ich habe verschiedene Dateien mit Matrizen unterschiedlicher Größe. Je Datei sind bleibt die Größe konstant.

    Dann vielleicht so als primitiver Ansatz:

    int main()
    {
        std::size_t columns = 0;
        //Anzahl Spalten ermitteln
        {
            std::ifstream reader("N_rand_10k_x_10k.txt");
            std::string line;
            std::getline(reader, line);
            std::istringstream isstr(line);
            double dummy;
            while(isstr >> dummy)
            {
                ++columns;
            }
        }
        //Hier beginnt das eigentliche Einlesen
        std::ifstream reader("N_rand_10k_x_10k.txt");
        std::vector<double> row(columns);
        std::size_t current_column = 0;
        std::size_t current_row = 0;
        while(reader >> row[current_column])
        {
            ++current_column;
            if(current_column == columns)
            {
                current_column = 0;
                //assign to matrix here
                ++current_row;
            }        
        }
    
    }
    

  • Mod

    Ach, oben habe ich bei dem Beispiel auch das rdbuf() vergessen. 'Tschuldigung. So geht das:

    #include <iostream>
    #include <sstream>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
      ifstream infile("test.cc");
      stringstream buffer;
      buffer << infile.rdbuf();
      string line;
      while (getline(buffer,line))
        cout << line << '\n';
    }
    


  • Ich habe in der Zwischenzeit mal mapped_file ausprobiert

    #include <string>
    #include <cstdlib> // Für EXIT_SUCCESS
    #include <iostream>
    
    #include <boost/foreach.hpp>
    #include <boost/tokenizer.hpp>
    #include <boost/lexical_cast.hpp>
    #include <boost/numeric/ublas/io.hpp>
    #include <boost/iostreams/stream.hpp>
    #include <boost/numeric/ublas/matrix.hpp>
    #include <boost/numeric/ublas/matrix_proxy.hpp>
    #include <boost/iostreams/device/mapped_file.hpp>
    
    // Abkürzungen
    using boost::iostreams::stream;
    using namespace boost::numeric::ublas;
    using boost::iostreams::mapped_file_source;
    
    int main( int argc , char **argv ) 
    {
    	std::string line;
    	std::size_t row = 0;
    	boost::char_separator<char> sep( "\t" );
    
    	stream<mapped_file_source> infile_N(mapped_file_source("../N_rand_10k_x_10k.txt")); 
    
    	if ( ! infile_N.is_open() )
    	{
    		return EXIT_FAILURE;
    	}
    
    	stream<mapped_file_source> infile_w(mapped_file_source("../w_rand_10k_x_10k.txt"));
    
    	if ( ! infile_w.is_open() )
    	{
    		return EXIT_FAILURE;
    	}
    
    	vector<double> v ( 10000 );
    	matrix<double> N ( 10000 , 10000 );
    
    	while( getline( infile_N , line ) )
    	{
    		boost::tokenizer<boost::char_separator<char>> tokens( line , sep );
    
    		matrix_row<matrix<double> > mr ( N , row ); 
    
    		BOOST_FOREACH( std::string t , tokens )
    		{
    			double elem;
    
    			try
    			{
    				elem = boost::lexical_cast<double>( t );
    			}
    			catch ( const boost::bad_lexical_cast & )
    			{
    				return EXIT_FAILURE;
    			}
    			catch ( ... )
    			{
    				return EXIT_FAILURE;
    			}
    
    			v[row] = elem;
    		}
    
    		mr = v;
    
    		row++;
    	}
    
    	infile_N.close();
    
    	matrix<double> w ( 10000 , 1 );
    
    	row = 0;
    
    	while( ! infile_w.eof() )
    	{
    		getline(infile_w,line);		
    
    		try
    		{
    			w( row++ , 1 ) = boost::lexical_cast<double>( line );
    		}
    		catch ( const boost::bad_lexical_cast & )
    		{
    			return EXIT_FAILURE;
    		}
    		catch ( ... )
    		{
    			return EXIT_FAILURE;
    		}
    	}
    
    	infile_w.close();
    
    	return EXIT_SUCCESS;
    }
    

    Ist aber immer noch sehr langsam. Mir scheint als ob er diese mapped_file nicht wirklich in den Speicher lädt.



  • Tachyon schrieb:

    Dann vielleicht so als primitiver Ansatz:

    [quote="SeppJ"So geht das:[/quote]

    Habe jetzt mal beide Ansätze ausprobiert und alle laufen ungefähr gleich schnell. Der cast von 10.000 double Werten scheint nicht so schnell zu sein.

    Zumindest zeigt der Profiler dass getline() so gut wie keine Zeit mehr kostet.

    Danke für eure Hilfe !



  • wm schrieb:

    Tachyon schrieb:

    Dann vielleicht so als primitiver Ansatz:

    Habe jetzt mal beide Ansätze ausprobiert und alle laufen ungefähr gleich schnell. Der cast von 10.000 double Werten scheint nicht so schnell zu sein.

    Zumindest zeigt der Profiler dass getline() so gut wie keine Zeit mehr kostet.

    Danke für eure Hilfe !

    Hmm, 10000 Werte merkt man bei mit gar nicht. Die sind quasi instant verfügbar. Arbeitest Du im Debug-Modus?

    Außerdem könntest Du noch irgendwie so versuchen, direkt in die Matrix zu lasen:

    bool is_whitespace(char c)
    {
        std::locale loc;
        return std::isspace(c, loc);
    }
    
    int main()
    {
        std::ifstream reader("N_rand_10k_x_10k.txt");
        //Anzahl Zeilen
        std::istreambuf_iterator<char> end;
        std::istreambuf_iterator<char> i(reader.rdbuf());
        std::size_t rows = std::count(i, end, '\n');
        reader.seekg(0);
        //Anzahl Spalten
        std::string line;
        std::getline(reader, line);
        std::size_t cols = 1 + std::count_if(line.begin(), line.end(), is_whitespace);
        reader.seekg(0);
        //Matrix erstellen
        typedef boost::numeric::ublas::matrix<double> matrix_type;
        typedef boost::numeric::ublas::matrix_row<matrix_type> matrix_row_type;
        std::size_t current_row = 0;
        matrix_type m(rows, cols);
        matrix_row_type row(m, current_row);
        std::size_t current_col = 0;
        //Einlesen
        while( (current_row + 1) < m.size2() && (reader >> row[current_col]))
        {
            ++current_col;
            if(current_col == cols)
            {
                current_col = 0;
                ++current_row;
                row = matrix_row_type(m, current_row);
            }
        }
    }
    


  • Tachyon schrieb:

    Hmm, 10000 Werte merkt man bei mit gar nicht. Die sind quasi instant verfügbar. Arbeitest Du im Debug-Modus?

    Ich meine 10000 casts je Zeile. Auf meinem NB sind es etwa 100 Zeilen je Sekunde.


  • Mod

    Hast du eigentlich mal einen Profiler benutzt, was da so langsam ist? Oftmals ist das Ergebnis recht überraschend.



  • SeppJ schrieb:

    Hast du eigentlich mal einen Profiler benutzt, was da so langsam ist? Oftmals ist das Ergebnis recht überraschend.

    Ja, im Moment ist es das lexical_cast ... getline braucht < 5% soweit ich es noch in Erinnerung habe.


Anmelden zum Antworten