缓存失效 - 是否有一个通用解决方案?
“计算机科学只有两个难题:缓存失效和命名事情。”
菲尔卡尔顿
有没有一种通用的解决方案或方法来使缓存失效; 要知道一个条目何时陈旧,所以你保证总是得到新的数据?
例如,考虑从文件获取数据的函数getData()
。 它基于文件的最后修改时间对其进行缓存,每次调用它时都会进行检查。
然后添加第二个函数transformData()
来转换数据,并在下次调用该函数时缓存其结果。 它不知道该文件 - 如何添加依赖项,如果文件发生更改,该缓存将变为无效?
每次调用transformData()
都可以调用getData()
,并将其与用于构建缓存的值进行比较,但这可能最终代价非常高。
你所谈论的是终身依赖链,一件事依赖于另一件事,它可以在其控制之外进行修改。
如果你从a
, b
到c
有一个幂等函数,如果a
和b
是相同的,那么c
是相同的,但是检查b
的代价很高,那么你可以:
b
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
: b
和x
: a
的a
: b
关系相匹配,连续分层(如x
)就是微不足道a
。
然而,很有可能你会得到三个有效性完全独立(或循环)的输入,所以不可能分层。 这意味着标记为重要的行将不得不更改为
如果(endCache [a] 过期或不存在)
高速缓存失效的问题在于,我们不知情的情况下,情况发生了变化。 因此,在某些情况下,如果还有其他一些事情知道它并可以通知我们,则可能有解决方案。 在给定的示例中,getData函数可以挂接到文件系统,该文件系统知道文件的所有更改,而不管文件的哪个进程发生更改,并且此组件可以通知转换数据的组件。
我不认为有任何一般的魔术解决方案可以让问题消失。 但在很多实际情况下,很可能有机会将基于“投票”的方法转变为基于“中断”的方法,这可能会使问题简单地消失。
如果您每次进行转换时都要获取Data(),那么您已经消除了缓存的全部好处。
对于你的例子,这似乎是一个解决方案,当你生成转换后的数据,也存储文件的文件名和最后修改时间的文件(你已经存储了这个数据结构是由getData( ),因此您只需将该记录复制到transformData()返回的数据结构中,然后再次调用transformData()时,检查文件的上次修改时间。
链接地址: http://www.djcxy.com/p/47707.html上一篇: Cache Invalidation — Is there a General Solution?
下一篇: pros and cons?