Подтвердить что ты не робот

Читать входные файлы, как можно быстрее?

У меня есть множество текстовых файлов данных в виде чисел с плавающей запятой. Я ищу самый быстрый способ прочитать их на С++. Я могу изменить файл на двоичный, если это самый быстрый.

Было бы здорово, если бы вы могли дать мне подсказку или сослаться на сайт с полным объяснением. Я не знаю, есть ли библиотека, которая быстро работает. Даже если есть какое-либо программное обеспечение с открытым исходным кодом, которое выполняет эту работу, это было бы полезно.

4b9b3361

Ответ 1

Наличие двоичного файла - самый быстрый вариант. Не только вы можете прочитать его непосредственно в массиве с raw istream::read за одну операцию (что очень быстро), но вы даже можете сопоставить файл в памяти, если ваша ОС поддерживает его; вы можете использовать open/mmap для POSIX-систем, CreateFile/CreateFileMapping/MapViewOfFile для Windows или даже для кросс-платформенного решения Boost (спасибо @Cory Nelson за то, что указали его).

Быстрые и грязные примеры, предполагая, что файл содержит необработанное представление некоторого float s:

"Нормальный":

#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();

С общей памятью:

#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);

Ответ 2

Ваше узкое место находится в I/O. Вы хотите, чтобы программа считывала столько данных в память за наименьшее количество вызовов ввода-вывода. Например, чтение 256 номеров с одним fread выполняется быстрее 256 fread одного номера.

Если вы можете, отформатируйте файл данных в соответствии с представлением внутренней плавающей запятой целевой платформы или, по крайней мере, вашим представлением программы. Это уменьшает накладные расходы при переводе текстового представления во внутреннее представление.

Обход ОС и использование контроллера DMA для чтения в файлах данных, если это возможно. Чип DMA берет на себя бремя чтения данных в память с плеч процессора.

Компактный файл данных. Файл данных должен находиться в одном непрерывном наборе секторов на диске. Это уменьшит количество времени, затрачиваемого на различные области на физических пластинах.

Вы запросили эксклюзивный контроль над дисковым ресурсом и процессорами. Заблокируйте все другие несущественные задачи; повысить приоритет выполнения вашей программы.

Используйте несколько буферов, чтобы поддерживать дисковый накопитель. Большая часть времени проводится в ожидании ускорения и замедления жесткого диска. Ваша программа может обрабатывать данные, а что-то еще хранит данные в буфере, что приводит к...

Многопоточность. Создайте один поток для чтения в данных и предупредите задачу обработки, когда буфер не пуст.

Это должно занять некоторое время. Все другие оптимизации приведут к незначительному повышению производительности. (Например, доступ к контроллеру жесткого диска напрямую для передачи в один из ваших буферов.)

Ответ 3

Еще одно внимание к режиму компиляции. Я попытался разобрать файл с 1М строк. Режим отладки потреблял 50 секунд для анализа данных и добавления в мой контейнер. Режим деблокирования потребляется как минимум в десять раз быстрее, около 4 секунд. Ниже приведен код для чтения всего файла перед использованием istringstream для анализа данных в виде 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]);
}