Сериализация простых структур данных в C ++: оценка 1d против 2d представления - PullRequest
1 голос
/ 22 августа 2011

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

Рассматриваемая структура данных содержит несколько двумерных векторов с плавающей точкой:

vector<<vector float> > data;

Векторы компонентов в основном имеют одинаковый размер, но это не гарантия. Однако существует очень ограниченное количество вариаций в размерах компонентных векторов. Например, обычно 99% компонентных векторов будут одинакового размера, а остаток будет несколько кратным базовому размеру. Может быть возможно обрезать более длинные или дополнить более короткие векторы компонентов, но это может оказать негативное влияние на производительность программы в некоторых случаях.

Эти двумерные векторы обычно содержат несколько сотен тысяч компонентных векторов, тогда как каждый компонентный вектор обычно содержит 40 элементов.

Эти данные считываются один раз при первой загрузке программы, и после этого информация многократно повторяется, но никогда не изменяется.

С точки зрения того, как сериализовать эти данные, кажется, есть два очень очевидных варианта:

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

Я написал простую тестовую программу, чтобы попытаться получить общее представление о том, как эти варианты могут быть реализованы на практике:

run-serializer.cpp: http://pastebin.com/AzWivQDU

Serializer.h: http://pastebin.com/dvbqN1EY

Serializer.cpp: http://pastebin.com/0eDCg7sE

 
$ g++ -o run-serializer run-serializer.cpp Serializer.cpp 
$ ./run-serializer 500
Initializing tests...
Total elems: 11441408
Test binfile: test.bin
Binary write: 0.038397
Average runtimes for 500 iterations:

Binary 1d read: 0.0228143
Binary 2d read: 0.156756
1d iter time: 0.125914
2d iter time: 0.126896

Похоже, это указывает на то, что на моем ноутбуке и в моем примере реализации 2d версия занимает примерно в 8 раз больше, чем 1d версия. Не слишком удивительно, и для моих целей это разумное количество времени. Это также указывает на то, что, как и ожидалось, разница между временем 1d и временем 2d очень мала, но, возможно, версия 1d выигрывает smidgen.

Учитывая (потенциально) переменную длину векторов компонентов, я склонен придерживаться существующего двумерного подхода. Начальный процесс загрузки заметно медленнее, но все же довольно незначителен с точки зрения приложения. Похоже, итерация в любом случае не является проблемой, и двумерный подход означает, что мне не придется изменять любой другой код, использующий в настоящее время эти структуры данных.

Так что, я думаю, мой настоящий вопрос:

  • Являются ли эти тесты в целом разумными, и имеют ли смысл сделанные из них выводы?

Извиняюсь за скучность.

1 Ответ

1 голос
/ 22 августа 2011

Есть место для улучшения.

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

Использование времени стены в течение всей продолжительности исполняемого файла (или N вызовов исполняемого файла) на самом деле не так уж плохо. Он сырой, но в среднем должен быть достаточно большой образец.

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...