Когда создавать собственную буферную систему для ввода / вывода (C ++)? - PullRequest
6 голосов
/ 06 ноября 2008

Мне приходится иметь дело с очень большими текстовыми файлами (2 ГБ), обязательно читать / записывать их построчно. Писать 23 миллиона строк с использованием ofstream очень медленно, поэтому в начале я попытался ускорить процесс записи больших кусков строк в буфер памяти (например, 256 МБ или 512 МБ), а затем записать буфер в файл. , Это не сработало, производительность более или менее одинакова. У меня та же проблема с чтением файлов. Я знаю, что операции ввода-вывода буферизуются системой ввода-вывода STL, и это также зависит от политики планировщика диска (управляемой ОС, в моем случае Linux).

Есть идеи о том, как улучшить производительность?

PS: я думал об использовании фонового дочернего процесса (или потока) для чтения / записи фрагментов данных, пока программа обрабатывает данные, но я не знаю (главным образом в случае подпроцесса), будет ли это быть достойным

Ответы [ 7 ]

10 голосов
/ 06 ноября 2008

Файл объемом 2 ГБ довольно большой, и вам необходимо знать обо всех возможных областях, которые могут выступать в качестве узких мест:

  • Сам жесткий диск
  • Интерфейс жесткого диска (IDE / SATA / RAID / USB?)
  • Операционная система / файловая система
  • Библиотека C / C ++
  • Ваш код

Я бы начал с некоторых измерений:

  • Сколько времени занимает ваш код для чтения / записи файла объемом 2 ГБ,
  • Как быстро команда ' dd ' может читать и записывать на диск? Пример ...

    dd if=/dev/zero bs=1024 count=2000000 of=file_2GB

  • Сколько времени занимает запись / чтение, используя только большие вызовы fwrite () / fread ()

Предполагая, что ваш диск способен читать / записывать со скоростью около 40 Мбит / с (что, вероятно, является реалистичной цифрой для начала), файл объемом 2 ГБ не может работать быстрее, чем около 50 секунд.

Сколько времени это на самом деле занимает?

Привет, Родди, используя метод чтения fstream с файлами 1,1 ГБ и большими буферы (128,255 или 512 МБ), необходимые около 43-48 секунд и это то же самое используя fstream getline (построчно). CP копирует почти 2 минуты файл.

В этом случае вы привязаны к оборудованию. cp должен читать и писать, и будет искать туда-сюда по поверхности диска, как сумасшедший, когда это сделает. Так что (как вы видите) он будет более чем в два раза хуже, чем простой случай «чтения».

Для повышения скорости первое, что я попробую, это более быстрый жесткий диск или SSD.

Вы не сказали, что такое интерфейс диска? SATA в значительной степени самый простой / быстрый вариант. Также (очевидно, это ...) убедитесь, что диск физически находится на той же машине, на которой работает код, в противном случае вы подключены к сети ...

8 голосов
/ 06 ноября 2008

Я бы также предложил отображаемые в память файлы, но если вы собираетесь использовать boost, я думаю, что boost :: iostreams :: mapped_file лучше, чем boost :: interprocess.

5 голосов
/ 06 ноября 2008

Может быть, вам стоит заглянуть в отображенные в память файлы.

Проверьте их в этой библиотеке: Boost.Interprocess

3 голосов
/ 06 ноября 2008

Просто подумайте, но избегайте использования std :: endl, так как это приведет к сбросу до того, как буфер заполнится. Вместо этого используйте '\ n' для новой строки.

2 голосов
/ 06 ноября 2008

Не используйте new для выделения буфера следующим образом:

Попробуйте: std :: vector <>

unsigned int      buffer_size = 64 * 1024 * 1024; // 64 MB for instance.
std::vector<char> data_buffer(buffer_size);
_file->read(&data_buffer[0], buffer_size);

Также прочитайте статью о , используя подчеркивание в именах идентификаторов: . Обратите внимание, что ваш код в порядке, но.

1 голос
/ 06 ноября 2008

Использование getline () может быть неэффективным, поскольку может потребоваться несколько раз изменить размер строкового буфера при добавлении к нему данных из буфера потока. Вы можете сделать это более эффективным, предварительно изменив размер строки:

Также вы можете установить размер буфера iostreams либо очень большой, либо NULL (для небуферизованного)

// Unbuffered Accesses:
fstream file;
file.rdbuf()->pubsetbuf(NULL,0);
file.open("PLOP");

// Larger Buffer
std::vector<char>  buffer(64 * 1024 * 1024);
fstream            file;
file.rdbuf()->pubsetbuf(&buffer[0],buffer.size());
file.open("PLOP");

std::string   line;
line.reserve(64 * 1024 * 1024);

while(getline(file,line))
{
    // Do Stuff.
}
0 голосов
/ 06 ноября 2008

Если вы собираетесь буферизовать файл самостоятельно, то я бы посоветовал провести некоторое тестирование с использованием небуферизованного ввода-вывода (setvbuf для файла, который вы создали, может отключить буферизацию библиотеки).

По сути, если вы собираетесь буферизовать себя, вы хотите отключить буферизацию библиотеки, так как это только причинит вам боль. Я не знаю, есть ли способ сделать это для ввода / вывода STL, поэтому я рекомендую перейти к вводу / выводу уровня C.

...