缓存API是独特的,因为它们是不可变的缓存,任何会改变可变缓存中某些元数据的操作(TTL,使用数据等)都必须返回缓存的新实例。
在实际的缓存API之上,还构建了一个类似于“映射”的API,以便可以使用Clojure的get,assoc,dissoc操作,但这个界面可能会有一些奇怪的边缘情况,例如在检查项目是否在缓存中以及之后查找(并且发现它已“消失”)之间的竞态条件--尽管缓存本身是不可变的。这给上游消费者(如core.memoize)带来了问题,core.memoize必须包含自旋/重试逻辑,以避免错误地返回nil。
这就是为什么我添加了wrapped命名空间,该命名空间提供了一个更直观的“可变缓存”(通过将不可变缓存包装在原子中),但这些缓存的“安全”API并不是真正的“映射”类:lookup-or-miss是最安全的函数,提供避免竞态条件和重复执行的方式,但仍然可以进行按需查找,如果需要,可以(重新)计算所需的值。
在创建后能够“播种”缓存,即使用新的值哈希表是一个本质上是变异的操作,正如“驱逐”操作。有一个类似映射的get操作是一个便利之处,但只有当你愿意在请求的缓存条目已过期时得到nil(或“丢失”值)时,这才是个便利之处。
正如说明书中指出的:“核心缓存API难以正确使用。”它链接到
https://dev.to/dpsutton/exploring-the-core-cache-api-57al,该文档讨论了因将缓存视为“仅仅是映射”而导致的野外错误。