Haskell-простой способ кэширования вызова функции
у меня есть такие функции, как:
millionsOfCombinations = [[a, b, c, d] |
a <- filter (...some filter...) someListOfAs,
b <- (...some other filter...) someListOfBs,
c <- someListOfCs, d <- someListOfDs]
aLotOfCombinationsOfCombinations = [[comb1, comb2, comb3] |
comb1 <- millionsOfCombinations,
comb2 <- millionsOfCombinations,
comb3 <- someList,
...around 10 function calls to find if
[comb1, comb2, comb3] is actually useful]
оценка millionsOfCombinations
занимает 40 секунд. на очень быстрой рабочей станции. Оценка aLotOfCombinationsOfCombinations
!!0 заняло 2 дня : - (
как я могу ускорить этот код? До сих пор у меня было 2 идеи - использовать профайлер. Пробовал использовать myapp +RTS -sstderr
после компиляции с GHC, но получите пустой экран и не хотите ждать дней, пока он закончится.
2-я мысль была как-то кэшировать millionsOfCombinations
. Правильно ли я понимаю, что для каждого значения в aLotOfCombinationsOfCombinations
, millionsOfCombinations
получает оценку несколько раз? Если это так, как я могу кэшировать результат? Очевидно, я только начал изучать Хаскелла. Я знаю, что есть способ сделать кэширование вызовов с монадой, но я все еще не понимаю этих вещей.
2 ответов
использовать -fforce-recomp
, -O2
и -fllvm
флаги
если вы еще не, обязательно используйте вышеуказанные флаги. Обычно я бы не упоминал об этом, но недавно я видел некоторые вопросы, которые не знали, что мощная оптимизация не является дефолтом.
Профиль Ваш Код
на -sstderr
флаг не совсем профилирования. Когда люди говорят профилирование, они обычно говорят о профилировании кучи или профилировании времени через -prof
и -auto-all
флаги.
Избегайте Дорогостоящих Примитивов
Если вам нужен весь список в памяти (т. е. он не будет оптимизирован), рассмотрите распакованные векторы. Если Int
сделаю вместо Integer
, рассмотрим это (но Integer является разумным значением по умолчанию, когда вы не знаете!). Используйте преобразования worker/wrapping в нужное время. Если вы сильно опираетесь на Data.Map
, попробуйте использовать Data.HashMap
из неупорядоченных контейнеров библиотека. Этот список можно продолжать и продолжать, но поскольку у вас еще нет интуиции о том, куда идет ваше время вычислений, профилирование должно быть первым!
Я думаю, что нет никакой возможности. Обратите внимание, что время для создания списка растет с каждым задействованным списком. Таким образом, вы получите около 10000003 комбинации для проверки, что действительно занимает много времени. Кэширование списка возможно, но вряд ли что-то изменит, так как новые элементы могут быть созданы почти мгновенно. Единственный способ, вероятно, изменить алгоритм.
Если millionsOfCombinations
является константой (а не функцией с аргументами), она кэшируется автоматически. В противном случае сделайте его константой, используя предложение where:
aLotOfCombinationsOfCombinations = [[comb1, comb2, comb3] |
comb1 <- millionsOfCombinations,
comb2 <- millionsOfCombinations,
comb3 <- someList,
...around 10 function calls to find if
[comb1, comb2, comb3] is actually useful] where
millionsOfCombinations = makeCombination xyz