Возвращение в Хаскелл через четыре года после первого взгляда на него. Меня всегда так поражает выразительность, и я сбился с толку из-за моей неспособности предсказать производительность пространства/времени.
Как разогрев, я взял для перевода крошечной игрушечной программы, написанной на С++. Это о "обмане" в Scrabble. Вы вводите свою игру, и она выводит возможные слова, которые вы можете играть, с вашими письмами в одиночку или путем скрещивания буквы на доске.
Все это вращается вокруг словаря, который предварительно загружается при запуске. Затем слова сохраняются в виде списков на карте вместе с их анаграммами. Ключами являются строки отсортированных букв. Пример будет говорить более четко:
Key : "AEHPS" Value : ["HEAPS","PHASE","SHAPE"]
Версия С++ читает ~ 320000 слов словаря по одному, всего около 200 мс. Результирующая структура данных представляет собой хеш-карту, хранящуюся в array<99991, vector<string>>
, и занимает около 12 мегабайт памяти.
Версия Haskell считывает один и тот же словарь примерно за 5 секунд, а размер кучи программы вздувается до 400 мегабайт! Я изменил тип значения в Data.Map
от [String]
до [ByteString]
, чтобы сохранить некоторую память, и это привело к сокращению потребления памяти программы примерно до 290 мегабайт. Это все еще в 24 раза больше, чем моя версия на С++. Это больше, чем просто "накладные расходы", хотя Data.Map
является деревом вместо массива.
Поэтому я предполагаю, что я делаю что-то неправильно.
Весь модуль отображается здесь: (устаревшая ссылка)
Я полагаю, что моя проблема связана с тем, как Data.Map
создается постепенно, растут на предыдущих версиях самого себя? Или с самой структурой данных? Или что-то еще?
Я попробую другие решения, например Data.HashMap
, или заполнить Data.Map
с помощью fromListWith
. Тем не менее, я хотел бы рассказать о том, что происходит здесь. Спасибо за понимание!
Короткий ответ:
Использование Data.Map.Strict, заставляя оценивать элементы значения и сохраняя ключи как ByteStrings, тоже сделало чудо деления объема памяти почти на 3. Результат равен 100Meg, который только в два раза больше стандартного std::multimap<std::string, std::string>
в С++ для одного и того же набора данных. Однако нет ускорения. Git обновлен.
Спасибо всем, кто внес свой вклад, здесь есть интересные материалы!