En esta respuesta, quiero mostrarle algunos puntos de referencia que comparan tres formas en serie diferentes de leer datos en C ++, siendo la tercera la más rápida.
En el primer método utilizo un std :: istreambuf_iterator
, en el segundo leo el archivo línea por línea en un std :: vector
y en el tercero utilizo operaciones con sabor a C.
/ * compilar con g ++ -std = c ++ 11 -O2 read_files.cpp -o read_filestest el programa con el siguiente add if = / dev / aleatorio de =. / dummy5GiB bs = 1024 count = $ [1024 * 1024 * 5] para i en 0 1 2; hacer tiempo ./reading_files dummy5GiB $ i; done * / # include # include <fstream> <iostream> # include # include <vector> <cstring> // para STRCMP # include # include <string> <algorithm> // para minusing namespace std;! int main (int argc, char * argv []) {if (argc = 3) {cerr << "uso: read_files <path> <number 0 o 1 o 2> \ n"; return 1; } archivo ifstream (argv [1], ios :: in | ios :: binary); if (! file.is_open ()) {cerr << argv [1] << "archivo no abierto! \ n"; return 1; } cout << "--------------------------- \ n"; if (! strcmp (argv [2], "0")) {cout << "método 0 \ n"; vector<char> content ((std :: istreambuf_iterator<char> (archivo)), std :: istreambuf_iterator<char> ()); cout << content.size () << "bytes leídos \ n"; } else if (! strcmp (argv [2], "1")) {cout << "método 1 \ n"; línea de cuerda; vector<string> content; while (getline (archivo, línea)) {content.push_back (línea); }
cout << content.size () << "líneas leídas \ n"; } else if (! strcmp (argv [2], "2")) {cout << "método 2 \ n"; file.seekg (0, std :: ios :: end); unsigned long long file_size = file.tellg (); cout << "el tamaño del archivo es" << file_size << "\ n"; // máximo 5 GiB de memoria, para que quepa en mi RAM unsigned long long max_block_size = 1024ULL * 1024ULL * 1024ULL * 5; file.clear (); file.seekg (0, std :: ios :: beg); unsigned long long block_size = min (max_block_size, file_size); char * buffer = (char *) malloc (block_size * sizeof (char)); unsigned long long procesado = 0; while (! file.eof ()) {file.read (buffer, block_size); cout << "leer un bloque de" << min (tamaño_archivo - procesado, tamaño_bloque) << "bytes \ n"; // trabaje aquí con el bloque en la memoria (si el tamaño del bloque es > 0) procesado + = block_size; } libre (búfer); } archivo.close (); return 0;}
En el tercer método leo el archivo en bloques de 5GiB, para que quepa en la RAM libre de mi máquina.
Aquí está el punto de referencia de el programa en un archivo de 5 GiB generado aleatoriamente.
bash-3.2 $ for i in 0 1 2; hacer tiempo ./reading_files dummy5GiB $ i; hecho --------------------------- método 05368709120 bytes readreal 0m35.194suser 0m19.665ssys 0m12.999s --------- ------------------ método 120973135 líneas readreal 0m40.478suser 0m34.046ssys 0m5.870s ------------------- -------- método 2 el tamaño del archivo es 5368709120 leer un bloque de 5368709120 bytes leer un bloque de 0 bytes real 0m4.413suser 0m1.757ssys 0m2.617s
Aquí está el punto de referencia en un archivo .bam real de 32GiB utilizando solo el tercer método, aquí la división del archivo leído juega un papel fundamental. No puedo decirte cuán grande es porque la memoria de mi disco duro se satura antes del final de la ejecución y entonces tengo que matar el programa.
time ./reading_files ./HG00252.mapped. ILLUMINA.bwa.GBR.low_coverage.20130415.bam 2 --------------------------- método 2 el tamaño del archivo es 34316054058 leer un bloque de 5368709120 bytes leer un Leer un bloque de 5368709120 bytes leer un bloque de 5368709120 bytes leer un bloque de 5368709120 bytes leer un bloque de 5368709120 bytes leer un bloque de 5368709120 bytes leer un bloque de 2103799338 bytes real 0m50.656suser 0m9.135ssys 0m35.728s
El El punto clave es minimizar las operaciones de archivo leyendo grandes bloques de datos a la vez (siempre que quepan en la memoria) y operar sobre ellos.
El uso de mmap
podría conducir a una mejora , pero no creo que sea tan grande como usar el tercer método en lugar de los dos primeros.