我目前正在玩弄clojure.core.cache,当存储在Atom
中的缓存中有缓存未命中时,我无法弄清楚如何对它进行原子设置和获取操作。
我正在尝试将基于时间的缓存引入我的 clojure 服务,一方面减少昂贵的数据库调用量,另一方面如果我只使用memoize
,则避免将来某个时间内存溢出(因为这应该是一个长时间运行的服务(。
现在在我看来,使用该库的正确方法是通过工厂函数之一创建一个缓存,将其存储在原子中,然后在我们更新它时交换新缓存。(请参阅下面的文档示例(
(require '[clojure.core.cache :as cache])
(def cache (atom (cache/fifo-cache-factory {:a 1, :b 2})))
(swap! cache cache/through-cache :d (constantly 13))
;=> {:a 1, :b 3, :d 13}
(swap! cache cache/evict :b)
;=> {:a 1, :d 13}
(get @cache :a)
;=> 1
现在我不明白的是如何进行原子设置和获取操作,即如何在必要时检索值和透明填充的缓存。
如果我通过 2 个操作执行此操作,根据我的理解,可能会导致竞争条件,因此在生产中使用是不安全的。
我错过了什么吗?
另外:我现在意识到获取和设置操作cache/through
是以原子方式完成的,因此每个get
操作都将返回相同的值。
Atoms 保证不会有竞争条件。
每次调用swap!
都在后台使用 CAS 操作。这就是为什么您需要在swap!
中提供的函数应该是无副作用的,因为如果另一个线程妨碍了更新原子,它可能会重试。
在swap!
中检索和填充through-cache
是正确的方法,也就是说,如果您需要保证对值的慢速检索操作只执行一次,您可能需要查看agents
。
请参阅 https://clojure.org/reference/agents 尤其是这部分: "如果在函数执行期间(直接或间接(进行了任何其他调度,它们将被保留,直到代理的状态被更改。