clojure - 在这种情况下突变的替代方案?
问题描述
我编写了一个计算密集型函数(下面的 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 函数后,我意识到它为最终用户会话产生了数百次相同的结果,这确实是一种资源浪费。
自然地,我倾向于考虑memoize,但不想在程序的整个生命周期中增加内存使用量;在所有用户会话中,缓存中可能有很多唯一数据,并且来自一个用户会话的数据对另一个用户会话无效。我的函数的“模型”参数似乎是缓存 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)是否有更好,更clojurey的方法来解决问题?
2)突变是否可能导致任何性能损失或其他缺陷?(我还没有大型数据集来测试性能)。
将不胜感激任何见解/评论。
PS 用户会话通常不超过 5 分钟,并且每个会话要存储在 get-cand-info 中的数据大小将低于 200 MB,一旦会话结束就可以进行 GC。
解决方案
我会按照你的建议去做。无需为此使用dosync
& 。只需在每个. 当模型不再被使用时,它可以被 GC'd。alter
ref
atom
model
更新
Java 的一种替代方法是使用 LinkedHashMap。您可以设置最大大小并覆盖该removeEldestEntry()
函数以控制行为。
请注意,此语法略有偏差,但我相信您知道如何修复它:
((deref...
推荐阅读
- python - 如何使类的字段与构造函数中的参数具有相同的类型
- android - ./gradlew:没有这样的文件或目录 bitbucket android 图像
- php - 为什么从数据库中检索数据后动态添加部分不起作用?
- php - Laravel - 干预图像停止我的 cron 工作
- python - 如何获取结果值
- javascript - How to open only 1 accordion at one time
- php - 如何保护 Laravel Glide 库?
- java - 如何在两个迭代器之间切换?
- python - 判断一个模型是pytorch模型还是tensorflow模型还是scikit模型
- arrays - 使用指针数组的拼写检查程序