La forma habitual de leer un archivo en C++ es éste:forma elegante de leer un archivo en C++: problema de rendimiento extraña
std::ifstream file("file.txt", std::ios::binary | std::ios::ate);
std::vector<char> data(file.tellg());
file.seekg(0, std::ios::beg);
file.read(data.data(), data.size());
La lectura de un archivo de 1,6 MB es casi instantánea.
Pero recientemente, descubrí std::istream_iterator y quería probarlo para codificar una hermosa forma de una línea para leer el contenido de un archivo. De esta manera:
std::vector<char> data(std::istream_iterator<char>(std::ifstream("file.txt", std::ios::binary)), std::istream_iterator<char>());
El código es agradable, pero muy lento. Toma aproximadamente 2/3 segundos leer el mismo archivo de 1.6 MB. Entiendo que puede que no sea la mejor manera de leer un archivo, pero ¿por qué es tan lento?
La lectura de un archivo de una manera clásica dice así (estoy hablando sólo de la función de lectura):
- la istream contiene una filebuf que contiene un bloque de datos desde el archivo
- la la función de lectura llama al sgetn desde el archivo bbuf, que copia los caracteres uno a uno (sin memcpy) desde el búfer interno al búfer de "datos"
- cuando los datos dentro del archivo bbu se leen por completo, el archivo lee el bloque siguiente desde el archivo
Cuando se lee un archivo usando istream_iterator, que dice así:
- el vector de llamadas * iterador para obtener el siguiente char (esto simplemente lee una variable), lo añade al final y aumenta su propia tamaño
- si el espacio asignado del vector está lleno (lo que ocurre con poca frecuencia), se realiza una reubicación
- y luego llama al iterador ++ que lee el siguiente carácter de la secuencia (operador >> con un parámetro char, que Ciertamente, solo llama a la función sbumpc de filebuf)
- finalmente se compara el iterador con el iterador final, que se realiza mediante la comparación de dos punteros
Debo admitir que la segunda forma no es muy eficiente, pero es al menos 200 veces más lenta que la primera manera, ¿cómo es posible ?
Pensé que el factor determinante del rendimiento eran las reubicaciones o el inserto, pero traté de crear un vector completo y de llamar a std :: copy, y es igual de lento.
// also very slow:
std::vector<char> data2(1730608);
std::copy(std::istream_iterator<char>(std::ifstream("file.txt", std::ios::binary)), std::istream_iterator<char>(), data2.begin());
"Pensé que el factor determinante del rendimiento eran las reubicaciones o el inserto": esta es la razón por la que debe confiar en los perfiles. –