2011-07-19 29 views
13

Tengo numerosos archivos de texto de datos en forma de números flotantes. Estoy buscando la manera más rápida de leerlos en C++. Puedo cambiar el archivo a binario si es el más rápido.leer archivos de entrada, de la manera más rápida posible?

Sería genial si pudiera darme una pista o referirme a un sitio web con una explicación completa. No sé si hay alguna biblioteca que haga el trabajo rápido. Incluso si hay algún software de código abierto que haga el trabajo, sería útil.

+2

Por favor, no etiquetar preguntas C++ como 'C'. Eso es simplemente molesto. –

Respuesta

24

Tener un archivo binario es la opción más rápida. No solo puede leerlo directamente en una matriz con istream::read sin procesar en una sola operación (lo cual es muy rápido), sino que incluso puede asignar el archivo en la memoria si su sistema operativo lo admite; puede usar open/mmap en sistemas POSIX, CreateFile/CreateFileMapping/MapViewOfFile en Windows, o incluso la solución multiplataforma Boost (gracias @Cory Nelson por señalarlo).

Quick & ejemplos sucios, suponiendo que el archivo contiene la representación cruda de algunos float s:

"Normal" leer:

#include <fstream> 
#include <vector> 

// ... 

// Open the stream 
std::ifstream is("input.dat"); 
// Determine the file length 
is.seekg(0, std:ios_base::end); 
std::size_t size=is.tellg(); 
is.seekg(0, std::ios_base::beg); 
// Create a vector to store the data 
std::vector<float> v(size/sizeof(float)); 
// Load the data 
is.read((char*) &v[0], size); 
// Close the file 
is.close(); 

Con memoria compartida:

#include <boost/interprocess/file_mapping.hpp> 
#include <boost/interprocess/mapped_region.hpp> 

using boost::interprocess; 

// .... 

// Create the file mapping 
file_mapping fm("input.dat", read_only); 
// Map the file in memory 
mapped_region region(fm, read_only); 
// Get the address where the file has been mapped 
float * addr = (float *)region.get_address(); 
std::size_t elements = region.get_size()/sizeof(float); 
+5

[Boost Interprocess] (http://www.boost.org/doc/libs/1_47_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file) proporciona archivos mapeados en memoria multiplataforma. –

+0

@Cory: uh, lindo, no sabía que Boost también. –

+0

la asignación de memoria va a ser muy rápida si el archivo ya está en caché. si no, 'leer' lo superará. –

5

Su cuello de botella está en la E/S. Desea que el programa lea tantos datos en la memoria en la menor cantidad de llamadas de E/S. Por ejemplo, leer 256 números con un fread es más rápido que 256 fread de un número.

Si puede, formatee el archivo de datos para que coincida con la representación de coma flotante interna de la plataforma de destino, o al menos la representación de su programa. Esto reduce la sobrecarga de traducir la representación textual a la representación interna.

Omitir el sistema operativo y usar el controlador DMA para leer los datos del archivo, si es posible. El chip DMA toma la carga de leer datos en la memoria de los hombros del procesador.

Compacte su archivo de datos. El archivo de datos quiere estar en un conjunto contiguo de sectores en el disco. Esto reducirá la cantidad de tiempo dedicado a buscar diferentes áreas en los platos físicos.

¿Ha programado demanda de control exclusivo sobre el recurso de disco y los procesadores. Bloquea todas las demás tareas sin importancia; elevar la prioridad de la ejecución de su programa.

Utilice varios búferes para mantener el disco girando. Una gran parte del tiempo se usa para esperar a que el disco duro se acelere y desacelere. Su programa puede procesar los datos mientras que otra parte está almacenando los datos en un búfer, lo que lleva a ...

De múltiples hilos. Cree un hilo para leer en los datos y alertar a la tarea de procesamiento cuando el búfer no está vacío.

Esto debería mantenerte ocupado por un tiempo. Todas las otras optimizaciones darán lugar a ganancias de rendimiento insignificantes. (Por ejemplo, acceder directamente al controlador del disco duro para transferirlo a uno de sus buffers.)

+0

interesante ..... – tomasz

+1

El OP tiene un archivo de texto. Speedup # 2, convertir ese archivo de texto a binario, va a acelerar las cosas inmensamente. Sigue con el # 1, lee todo lo que puedas de un trago. Todo después de eso es salsa. –

2

Otra atención al modo de compilación. He intentado analizar un archivo con líneas de 1M. El modo de depuración consumió 50 segundos para analizar los datos y anexarlos a mi contenedor. El modo de lanzamiento se consumió al menos diez veces más rápido, alrededor de 4 segundos. El siguiente código es para leer todo el archivo antes de usar istringstream para analizar los datos como puntos 2D (,).

vector <float> in_data; 
string raw_data; 

ifstream ifs; 
ifs.open(_file_in.c_str(), ios::binary); 
ifs.seekg(0, ios::end); 
long length = ifs.tellg(); 
ifs.seekg(0, ios::beg); 
char * buffer; 
buffer = new char[length]; 
ifs.read(buffer, length); 
raw_data = buffer; 
ifs.close(); 
delete[]buffer; 
cout << "Size: " << raw_data.length()/1024/1024.0 << "Mb" << endl; 
istringstream _sstr(raw_data); 
string _line; 

while (getline(_sstr, _line)){ 
    istringstream _ss(_line); 
    vector <float> record; 
    //maybe using boost/Tokenizer is a good idea ... 
    while (_ss) 
    { 
     string s; 
     if (!getline(_ss, s, ',')) break; 
     record.push_back(atof(s.c_str())); 
    } 
    in_data.push_back(record[0]); 
} 
Cuestiones relacionadas