一尘不染

缓存无效-是否有通用解决方案?

algorithm

“计算机科学中只有两个难题:缓存失效和命名。”

菲尔·卡尔顿

是否有使缓存无效的一般解决方案或方法;知道什么时候条目是陈旧的,所以可以保证您总是能获得最新数据?

例如,考虑一个getData()从文件获取数据的函数。它根据文件的上次修改时间对其进行缓存,并在每次调用时对其进行检查。
然后,添加第二个函数transformData()来转换数据,并缓存其结果,以备下次调用该函数时使用。它不知道文件-
如何添加依赖项,如果文件被更改,此缓存将变为无效?

您可以在getData()每次调用时transformData()进行调用,并将其与用于构建缓存的值进行比较,但这最终可能会非常昂贵。


阅读 194

收藏
2020-07-28

共1个答案

一尘不染

您正在谈论的是生命周期依赖链,一件事依赖于另一件事,可以在其控制范围之外进行修改。

如果你有一个幂函数,从abc那里,如果ab相同,则c是相同的,但检查的成本b是高的,那么你可以:

  1. 接受您有时会使用过时的信息进行操作,并且不要总是检查 b
  2. 尽最大可能使检查b尽快

你不能吃蛋糕也不能吃…

如果您可以a在顶部放置一个额外的缓存,那么这将对最初的问题产生一点影响。如果您选择1,那么您将拥有任意的自由度,因此可以缓存更多,但必须记住要考虑缓存值的有效性b。如果选择2,则您仍必须b每次都检查一次,但可以退回缓存以检查a是否b签出。

如果您分层缓存,则必须考虑是否由于综合行为而违反了系统的“规则”。

如果您知道a始终有效b,那么您可以这样安排您的缓存(伪代码):

private map<b,map<a,c>> cache // 
private func realFunction    // (a,b) -> c

get(a, b) 
{
    c result;
    map<a,c> endCache;
    if (cache[b] expired or not present)
    {
        remove all b -> * entries in cache;   
        endCache = new map<a,c>();      
        add to cache b -> endCache;
    }
    else
    {
        endCache = cache[b];     
    }
    if (endCache[a] not present)     // important line
    {
        result = realFunction(a,b); 
        endCache[a] = result;
    }
    else   
    {
        result = endCache[a];
    }
    return result;
}

显然x,只要在每个阶段新添加的输入的有效性与:和:的ab关系匹配,连续的分层(say )都是微不足道的。x``b``x``a

但是,您很有可能获得三个输入,其有效性完全独立(或循环),因此不可能分层。这意味着标记为//重要的行必须更改为

如果(endCache [a] 过期或 不存在)

2020-07-28