Каждый раз, когда я упоминаю низкую производительность iostreams стандартной библиотеки C ++, я встречаю волну недоверия. Тем не менее, у меня есть результаты профилировщика, показывающие большие количество времени, затрачиваемое на код библиотеки iostream (полная оптимизация компилятора), и переключение с iostreams на специфичные для ОС API ввода-вывода и настраиваемое управление буфером дает улучшение на порядок.
Какую дополнительную работу выполняет стандартная библиотека C ++ , требуется ли это по стандарту, и полезно ли это на практике? Или некоторые компиляторы предоставляют реализации iostreams, которые конкурируют с ручным управлением буфером?
Чтобы сдвинуть дело с мертвой точки, я написал несколько коротких программ для проверки внутренней буферизации iostreams:
ostringstream
http://ideone.com/2PPYw char []
буфер http://ideone.com/Ni5ct вектор
с помощью back_inserter
http://ideone.com/Mj2Fi vector
простой итератор http://ideone.com/9iitv строковом буфере
http://ideone.com/qc9QA вектор
простой итератор плюс проверка границ http://ideone.com/YyrKy Обратите внимание, что версии ostringstream
и stringbuf
выполняют меньше итераций, потому что они слишком медленнее.
На ideone ostringstream
примерно в 3 раза медленнее, чем std: copy
+ back_inserter
+ std :: vector
и примерно в 15 раз медленнее, чем memcpy
в необработанный буфер. Это похоже на профилирование до и после, когда я переключил свое настоящее приложение на настраиваемую буферизацию.
Это все буферы в памяти, поэтому медленность iostreams не может быть связана с медленным дисковым вводом-выводом, слишком сильно очистка, синхронизация с stdio или любые другие вещи, которые люди используют для оправдания наблюдаемой медлительности стандартной библиотеки C ++ iostream.
Было бы неплохо увидеть тесты производительности в других системах и комментарии о том, что делают обычные реализации (например, gcc libc ++, Visual C ++, Intel C ++) и сколько накладных расходов предусмотрено стандартом.
Ряд людей правильно указали, что iostreams чаще используются для форматированного вывода. Однако они также являются единственным современным API, предоставляемым стандартом C ++ для доступа к двоичным файлам. Но настоящая причина для проведения тестов производительности внутренней буферизации относится к типичному форматированному вводу-выводу: если iostreams не может поддерживать контроллер диска с необработанными данными, как они могут поддерживать его, если они также несут ответственность за форматирование?
Все это на итерацию внешнего ( k
) цикла.
На ideone (gcc-4.3.4, Пробежал все дважды, чтобы увидеть, насколько стабильными были результаты. Довольно согласованный IMO.
ПРИМЕЧАНИЕ: на моем ноутбуке, поскольку я могу сэкономить больше процессорного времени, чем позволяет ideone, я установил количество итераций на 1000 для всех методов. Это означает, что перераспределение ostringstream
и вектора
, которое происходит только на первом проходе, не должно иметь большого влияния на окончательные результаты.
РЕДАКТИРОВАТЬ: К сожалению, обнаружена ошибка в файле vector
-with-normal-iterator, итератор не продвигался, и поэтому было слишком много попаданий в кэш. Мне было интересно, насколько vector
превосходит char []
. Это не имело большого значения, vector
по-прежнему быстрее, чем char []
в VC ++ 2010.
Буферизация выходных потоков требует трех шагов каждый раз при добавлении данных:
Последний опубликованный мной фрагмент кода « vector
простой итератор плюс проверка границ» не только делает это, но и выделяет дополнительное пространство и перемещает существующие данные, когда входящий блок не подходит. Как указал Клиффорд, буферизация в классе файлового ввода-вывода не должна этого делать, она просто очищает текущий буфер и повторно использует его. Таким образом, это должна быть верхняя граница стоимости буферизации вывода. И это именно то, что нужно для создания рабочего буфера в памяти.
Так почему же stringbuf
в 2,5 раза медленнее на ideone, и как минимум в 10 раз медленнее при тестировании? В этом простом микро-тесте он не используется полиморфно, поэтому это не объясняет.