缓存API是很特别的。由于它们是不可变的缓存,任何通常会改变可变缓存中某些元数据(TTL、使用数据等)的操作必须返回缓存的新实例。
除了实际的缓存API之外,还构建了一个类似于“映射”的API,以便可以使用Clojure的get、assoc、dissoc操作,但是这个外观确实有一些奇怪的边缘情况,例如在检查项目是否在缓存中以及随后查找(并发现它已“消失”)之间存在竞争条件,尽管缓存本身是不可变的。这给流式消费者带来问题,如core.memoize,它必须包含spin/retry逻辑来避免错误地返回nil。
这就是为什么我添加了用于提供更直观的“可变缓存”的包装命名空间(通过在不可变缓存中包装原子),但这些缓存的“安全”API并不真正是“映射”式的:lookup-or-miss是该API中最重要的函数,它能够避免竞争条件和反复执行,同时在需要时能够按需查找可以(重新)计算所需值。
能够在创建后使用新的哈希表值“种子”缓存,这是一个内在的变异操作,就像“逐出”一样。具有“类似映射”的get操作是一种便利,但只有当你愿意为已过期的请求缓存条目得到nil(或“缺少”值)时,这种便利才是有用的。
如README笔记中所述:“core.cache API难以正确使用。”,并链接到这篇文章
https://dev.to/dpsutton/exploring-the-core-cache-api-57al,讨论了将缓存视为“仅仅是一个映射”所导致的现实世界中的错误。