Улучшает ли увеличенная буферизация максимальную скорость ifstream.getline() в C++?

Непосредственно перед использованием MSVC++ input.getline() для чтения очень большого (3 ГБ) текстового файла с разделителями я хотел оптимизировать скорость, увеличив размер входного буфера:

    ifstream input("in1.txt");
    input.rdbuf()->pubsetbuf(NULL, 1024 * 1024);

Однако при выполнении кода скорость не улучшилась, поэтому хотелось бы знать:

  • Что не так в коде?
  • Работает ли буферизация с ifstream.getline?
  • Каков размер буферизации по умолчанию, назначенный для ifstream?

С Уважением.


person vizcayno    schedule 23.02.2012    source источник


Ответы (5)


Рассматривали ли вы системный вызов mmap()?

Функция mmap() должна установить отображение между адресным пространством процесса и файлом, объектом разделяемой памяти или объектом типизированной памяти. Формат вызова следующий:

pa=mmap(addr, len, prot, flags, fildes, off);

справочная страница

MapViewOfFile — эквивалент Windows.

LPVOID WINAPI MapViewOfFile( __in  HANDLE hFileMappingObject,
__in  DWORD dwDesiredAccess, __in  DWORD dwFileOffsetHigh, __in  DWORD dwFileOffsetLow, __in  SIZE_T dwNumberOfBytesToMap );

person yves Baumes    schedule 23.02.2012
comment
Айвз, спасибо за помощь! хотя код для windows выглядит ужасно и очень близко к C. Я не могу поверить, что невозможно улучшить скорость с помощью STL. - person vizcayno; 24.02.2012

Суть буферизации в том, что она работает на многих уровнях, у вас есть буферизация на уровне библиотеки (ifstream), у вас есть буферизация на уровне ОС и буферизация на аппаратном уровне. Изменение размера любого из них может оказать существенное или несуществующее влияние на производительность.

Что правда, так это то, что «логика» программы будет намного быстрее, чем у IO.

Лично, если горлышко бутылки не серьезно, я бы оставил его в покое.

person 111111    schedule 23.02.2012
comment
«логика» программы будет намного быстрее, чем у IO. Это распространенное предположение, которое никто никогда не проверяет. Они просто используют это как предлог, чтобы не ускорять ввод-вывод. В результате того, что вы никогда не беспокоитесь о производительности ввода-вывода, он действительно очень медленный. - person Ben Voigt; 24.02.2012
comment
@BenVoigt: +1 Я согласен!. С появлением на рынке сетевых адаптеров 10g и 40g ввод-вывод фактически загружает ЦП, логика быстро становится узким местом, а тупая/неэффективная обработка ввода в логике является причиной большинства замедлений. - person Sami Kenjat; 12.11.2012

Вы получите самую высокую производительность, используя CreateFile и ReadFile. Откройте файл с помощью FILE_FLAGS_SEQUENTIAL_SCAN.

Чтение с размером буфера, равным степени двойки. Только бенчмаркинг может определить это число. Однажды я видел, что это 8K. В другой раз я обнаружил, что это 8M! Это сильно варьируется.

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

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

person usr    schedule 23.02.2012
comment
Принятые ответы объясняют, почему это так. Он также не использовал FILE_FLAG_SEQUENTIAL_SCAN. - person usr; 24.02.2012
comment
Да, я сказал ему об этом в комментариях. Но тот факт, что MapViewOfFile выполняется немного быстрее, чем FILE_FLAG_NO_BUFFERING, показывает, что отображение памяти либо намного эффективнее, чем ReadFile, возможно, из-за отсутствия необходимости копировать все из кеша на частную страницу, принадлежащую приложению, либо отображение памяти выполняет собственную предварительную выборку (которая была отключена для ReadFile в этом вопросе), или, возможно, некоторые из них. - person Ben Voigt; 24.02.2012
comment
Да, отображение памяти выполняет предварительную выборку самостоятельно. По крайней мере, согласно книге Windows Internals. Cache Manager может даже обнаруживать определенные шаблоны доступа. Он автоматически переключается в режим SEQUENTIAL или RANDOM_ACCESS внутри. - person usr; 24.02.2012
comment
FILE_FLAG_NO_BUFFERING означает, что вы получаете поиск по диску для каждого блока, потому что предварительная выборка не держит диск занятым. - person usr; 24.02.2012

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

person Dmitri Bouianov    schedule 23.02.2012

Я хотел оптимизировать скорость

Избавьтесь от fstream. iostreams вообще ужасное узкое место.

person Ben Voigt    schedule 23.02.2012
comment
Бен, тесты Google убедили меня, что C++ — самый быстрый язык, и, конечно же, он включает в себя STL :-( - person vizcayno; 24.02.2012
comment
@ user255053: Я серьезно сомневаюсь, что вы используете STL, и даже если вы используете, iostreams никогда не были его частью. ‹/pedant› Стандартная библиотека C++ может быть оптимизирована или нет, в зависимости от реализации и используемой части. - person Ben Voigt; 24.02.2012