Каков наилучший способ для бинаризации данных
У меня есть некоторые файлы данных, которые записываются как tag = value, где tag это строка, а value может быть числовым, string, array и т. Д. Я использую этот формат, потому что он читается и может быть легко отредактирован. Теперь у каждого класса, который создается с использованием этого формата, есть метод load, и он читает нужные теги и использует значения, найденные в этих тегах. Я хочу сделать двоичные данные для увеличения скорости загрузки. Одним из способов было бы использование метода ToBinary (имя не имеет значения) в каждом классе, который считывает старые данные и записывает их в файл, а новый файл используется для создания экземпляра объекта. Это можно сделать в автономном режиме, только один раз / приложение. У вас есть другие предложения для этого? Я использую C++ для этого.
Редактировать: я думаю, что самая дорогая часть сейчас - это анализ файла при первом чтении, а затем поиск нужного мне тега, а не чтение файла с диска. Я могу использовать пользовательскую файловую систему, чтобы иметь несколько маленьких файлов в одном большом файле.
6 ответов
Для этого у меня есть базовый класс сериализации с функциями To/From с небольшим заголовком, в который можно встроить обработку версий. Я думаю, что это хорошая система для более простых данных, которые должны храниться локально и в большинстве случаев "только для чтения".
Что-то вроде этого:
class SeralizeMe
{
public:
virtual bool To(Archive &file)=0;
virtual bool From(Archive &file)=0;
virtual bool NeedsSave(void)=0;
};
Однако не используйте эту систему, если вы:
- Необходимо часто менять формат.
- Необходимо выбрать, какие данные загружать и что хранить.
- Используйте большие файлы, которые особенно чувствительны к сбоям питания при сохранении.
Если применимо что-либо из вышеперечисленного, используйте базу данных, подходящим конкурентом будет встроенный FirebirdSQL.
Я не использовал его раньше, но я уверен, что модуль Сериализации Boost - хорошее место для начала.
Если вы используете файл, то использование двоичных данных, вероятно, не значительно улучшит ваши характеристики, если только у вас нет очень большого куска данных для хранения в файле (изображения, видео...).
Но в любом случае вы можете использовать двоичный алгоритм сериализации, такой как Boost.
Если вы хотите улучшить производительность, вам придется использовать поля фиксированной длины. Разбор или загрузка полей переменной длины не обеспечивает значительного увеличения производительности. Чтение по текстовой строке включает сканирование токена конца строки. Сканирование тратит время.
Прежде чем использовать любое из следующих предложений, профилируйте свой код, чтобы установить базовое время или число для производительности. Делайте это после каждого предложения, так как оно позволит вам рассчитать дельту производительности каждой оптимизации. Я прогнозирую, что дельта будет уменьшаться с каждой оптимизацией.
Я предлагаю сначала преобразовать файл в записи фиксированной длины, все еще используя текст. Заполните поля пробелами по мере необходимости. Таким образом, зная размер записи, вы можете заблокировать чтение в памяти и обрабатывать память как массив. Это должно обеспечить значительное улучшение.
На этом этапе вашими узкими местами по-прежнему остаются скорость ввода-вывода в файл, которую вы не можете существенно улучшить (поскольку файловый ввод-вывод контролируется ОС), а также сканирование / преобразование текста. Некоторые дальнейшие оптимизации: преобразование текста в числа и, наконец, преобразование в двоичный файл. Любой ценой предпочитайте хранить файл данных в удобочитаемой форме.
Прежде чем сделать файл данных менее читабельным, попробуйте разбить ваше приложение на потоки. Один поток обрабатывает графический интерфейс, другой - ввод, а другой - для обработки. Идея состоит в том, чтобы процессор всегда выполнял часть вашего кода, а не ждал. На современных платформах файловый ввод / вывод может выполняться, пока процессор обрабатывает ваш код.
Если вы не заботитесь о переносимости, посмотрите, имеет ли ваша платформа возможность DMA (компонент DMA или Direct Memory Access позволяет передавать данные без использования процессора или минимизируя использование процессора). Следует обратить внимание на то, что многие платформы разделяют адрес и шину данных между процессором и DMA. Таким образом, один компонент заблокирован или приостановлен, в то время как другой использует адрес и шины данных. Так что может помочь или нет. Зависит от того, как платформа подключена.
Преобразовать поле ключа, чтобы использовать числа, или токены. Поскольку токены являются числовыми, они могут использоваться в качестве индексов в таблицах переходов (также для переключения операторов) или просто в качестве индексов в массивах.
В крайнем случае, конвертируйте файл в двоичный файл. Двоичная версия должна иметь два поля: ключ как токен и значение. Переносить данные большими кусками в память.
Резюме
- Перетащите большие блоки данных в память.
- Профиль, прежде чем вносить изменения, чтобы установить базовое измерение производительности.
- Оптимизируйте один шаг за раз, профилируя после каждой оптимизации.
- Предпочитают хранить файл данных в удобочитаемой форме.
- Минимизируйте изменения в файле данных.
- Конвертировать файл для использования полей фиксированной длины.
- Попробуйте использовать потоки или многозадачность, чтобы приложение не ожидало.
- Преобразование текста в числовые токены (уменьшает удобочитаемость)
- Конвертировать данные в двоичный файл в качестве крайней меры (людям очень трудно читать и отлаживать).
Еще один протобуф от Google. Не самый быстрый, но он может поддерживать развивающиеся типы данных и очень эффективен в сети и поддерживает другие языки.
Ссылка здесь.
У меня есть две идеи для вас:
1) Если список тегов является постоянным и известен заранее, вы можете преобразовать каждый из них в BYTE (или WORD), за которым следует длина значения (в байтах), за которой следует необработанная c-строка значения полезная нагрузка.
Например, учитывая следующее:
Tag1 = "hello World!" // 12 bytes in length (achieved by "strlen(value) * sizeof(char)" )
Tag2 = "hello canada!" // 13 bytes in length
Вы можете превратить это в поток байтов:
0x0001 0x000B // followed by 12 bytes representing the 'value' // 0x0002 0x000C // followed by 13 bytes representing 'value2'
Ваша программа просто должна знать, что заголовок WORD "0x0001" представляет Tag1, а заголовок "0x0002" представляет Tag2.
Вы можете даже дополнительно абстрагировать имена тегов, если не знаете их заранее, следуя аналогичной длине, структуре значений.
2) Возможно, медленный бит - это просто ваша реализация парсинга текста? Подумайте об использовании специальной библиотеки с открытым исходным кодом для того, что вы пытаетесь сделать. Пример: " boost:: property_tree"
Дерево свойств специально разработано для хранения и извлечения пар ключ-значение (предназначено для использования в качестве файла настроек конфигурации). Но я думаю, это будет зависеть от того, сколько таких пар вы пытаетесь сохранить, чтобы это было экономичным.