Хранение больших таблиц поиска - PullRequest
0 голосов
/ 21 июля 2009

Я занимаюсь разработкой приложения, которое использует очень большие справочные таблицы для ускорения математических вычислений. Самая большая из этих таблиц - int [], в которой содержится ~ 10 миллионов записей. Не все таблицы поиска являются int []. Например, один из них - словарь с ~ 200 000 записей. В настоящее время я генерирую каждую таблицу поиска один раз (это занимает несколько минут) и сериализую ее на диск (со сжатием), используя следующий фрагмент:

    int[] lut = GenerateLUT();
    lut.Serialize("lut");

где Serialize определяется следующим образом:

    public static void Serialize(this object obj, string file)
    {
        using (FileStream stream = File.Open(file, FileMode.Create))
        {
            using (var gz = new GZipStream(stream, CompressionMode.Compress))
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(gz, obj);
            }
        }
    }

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

     int[] lut1 = (Dictionary<string, int>) Deserialize("lut1");
     int[] lut2 = (int[]) Deserialize("lut2");
 ...

где десериализация определяется как:

    public static object Deserialize(string file)
    {
        using (FileStream stream = File.Open(file, FileMode.Open))
        {
            using (var gz = new GZipStream(stream, CompressionMode.Decompress))
            {
                var formatter = new BinaryFormatter();
                return formatter.Deserialize(gz);
            }
        }
    }

Сначала я подумал, что, возможно, замедление было вызвано сжатием gzip, но его удаление заняло всего несколько сотен миллисекунд из процедур сериализации / десериализации.

Кто-нибудь может предложить способ ускорить время загрузки этих справочных таблиц при первом запуске приложения?

Ответы [ 5 ]

2 голосов
/ 21 июля 2009

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

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

Тем не менее, в зависимости от модели использования, база данных может быть лучшим подходом. Вы всегда можете сделать что-то, что было бы более ориентировано на базу данных, и создать таблицу поиска лениво из БД (то есть: поиск - это поиск в LUT, но если поиск не существует, загрузите его из БД и сохраните это в таблице). Это сделало бы запуск мгновенным (по крайней мере, с точки зрения LUT), и, вероятно, все еще сохранит поиск довольно быстро.

0 голосов
/ 21 июля 2009

Зачем их застегивать?

Диск больше ОЗУ.

Прямое двоичное чтение должно быть довольно быстрым.

0 голосов
/ 21 июля 2009

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

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

0 голосов
/ 21 июля 2009

Сколько данных мы здесь говорим? По моему опыту, чтение гигабайта с диска в память занимает около 20 секунд. Так что, если вы читаете больше половины гигабайта, вы почти наверняка столкнетесь с аппаратными ограничениями.

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

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

0 голосов
/ 21 июля 2009

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

...