Я написал вычислительно-интенсивную функцию (get-cand-info ниже), которая будет вызываться из ранее существующего кода clojure, написанного другими.
(defn get-cand-info [model tuple] ; my code which operates on 'tuple' and a hash-map called 'model'
; ....
cand-info)
;; how my code get-cand-info is going to be called
(defn get-cand-scores [model]
(let [tuples (make-tuples model)]
(filter identity
(pmap #(get-cand-info model %) tuples))))
(defn select-cand [model]
(let [cands-with-scores (get-cand-scores model)]
; Logic to work on cand-with-scores, finally returns one of
; the cand-info but not the model
))
После написания новой функции get-cand-info я понял, что она дает идентичный результат сотни раз для сеанса конечного пользователя, что на самом деле является пустой тратой ресурсов.
Естественно, я был склонен рассмотреть памятку , но не хотел увеличивать использование памяти в течение всей жизни программы; для всех пользовательских сессий в кеше может быть много уникальных данных, и данные из одной пользовательской сессии в любом случае недопустимы для другой пользовательской сессии. Параметр 'model' для моей функции казался идеальным местом для кэширования результата get-cand-info, поскольку он хранит данные за один сеанс.
Однако, если я возвращаю обновленную модель из своей функции, это меняет контракт того, что возвращает моя функция. Если я изменю контракт, чтобы вернуть новую карту «модель» с новым результатом, связанным с ним, мне нужно будет обновить код до самого стека вызовов - что означает изменение множества функций и чего-то, что я хочу чтобы избежать.
Поэтому я решил изменить модель и изменить ее в своем узле:
(defn get-cand [model tuple]
; Fetch the cand-info from the model if available there
(if-let [cand-info ((deref (:cand-info model)) tuple)]
cand-info
; Else calculate the cand-info,
; ....
;store it in the model and return it
(do
(swap! (:cand-info model) assoc tuple cand-info)
cand-info) ))
Это делает работу, но заставляет меня задуматься
1) Есть ли лучший, более хитрый способ решения проблемы?
2) Может ли мутация привести к снижению производительности или к другому недостатку? (У меня пока нет больших наборов данных для тестирования производительности).
Буду признателен за любые идеи / комментарии.
P.S. Сеансы пользователя обычно не превышают 5 минут, а размер данных, которые должны храниться в get-cand-info за сеанс, будет меньше 200 МБ, что может быть GCed, как только сеанс закончится.