читать входные файлы, как можно быстрее? - PullRequest
15 голосов
/ 20 июля 2011

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

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

Ответы [ 3 ]

27 голосов
/ 20 июля 2011

Наличие двоичного файла - самый быстрый вариант.Вы можете не только прочитать его непосредственно в массиве с необработанным 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);
7 голосов
/ 20 июля 2011

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

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

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

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

Требует ли ваша программа исключительного контроля над дисковым ресурсом и процессорами.Блокировать все другие неважные задачи;Повысьте приоритет выполнения вашей программы.

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

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

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

2 голосов
/ 29 апреля 2015

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