正确的数据结构用于(这个特定的)到期缓存?

时间:2010-06-20 21:45:51

标签: c++ algorithm caching

我需要读取一个非常大,高度相互关联的数据集,数据相当本地化,并且读取相当昂贵。具体做法是:

  1. 数据集大小为2gigs - 30gigs,因此我必须将文件的各个部分映射到内存中才能读取。与我在算法中完成的其他工作相比,这非常昂贵。从分析中我发现大约有60%的时间用于读取内存,因此这是开始优化的正确位置。
  2. 当对这个数据集进行操作时,我必须遵循它内部的链接(想象它类似于链接列表),虽然这些读取不能保证接近顺序,但它们是相当本地化的。这意味着:
  3. 比方说,我们一次运行2兆内存。如果你将2兆的数据读入内存,那么我将要做的大约40%的读取将在相同的2兆内存中。在其余数据中,大约20%的读取将是纯随机访问,而另外40%的读取很可能链接回2meg段,指向这一点。
  4. 从问题的知识和分析,我相信在程序中引入缓存将有很大帮助。我想要做的是创建一个缓存,其中包含N个大块的X兆内存(N和X可配置,因此我可以调整它),我可以先检查,然后再映射另一部分内存。此外,缓存中的某些内容越长,我们在短期内请求内存的可能性就越小,因此最旧的数据将需要过期。

    毕竟,我的问题很简单:哪种数据结构最适合实现这种性质的缓存?

    我需要非常快速的查找,以查看给定地址是否在缓存中。随着缓存的每次“遗漏”,我都希望使其中最老的成员到期,并添加一个新成员。但是,我打算尝试调整它(通过更改缓存的数量),使70%或更多的读取次数达到。

    我目前的想法是使用AVL树(用于搜索/插入/删除的LOG2 n)将是最安全的(没有退化情况)。我的另一个选择是稀疏哈希表,在最好的情况下查找将是O(1)。从理论上讲,这可能会退化为O(n),但实际上我可以保持较低的碰撞。这里需要关注的是查找和删除哈希表中最旧的条目需要多长时间。

    有没有人对这里最好的数据结构有什么想法或建议?为什么?

3 个答案:

答案 0 :(得分:3)

好像您正在寻找LRU (Least Recently Used)缓存:LRU cache design

答案 1 :(得分:2)

如果你的算法的60%是I / O,我建议实际的缓存设计并不那么重要 - 任何类型的缓存都可以大幅加速。

但是,设计很大程度上取决于您用来访问块的数据。 String,int等。如果你有一个int,你可以在一个链表中做一个hashmap,在高速缓存未命中时删除,擦除然后在高速缓存命中时按下它。

在许多实现中,以不同的名称(最常见的是无序映射)提供了散列图。 Boost有一个,TR1中有一个,等等.hash_map的一大优点是随着数字的增加,性能损失减少,关键值的灵活性也更高。

答案 2 :(得分:2)

将缓存放入两个排序的树中(AVL或任何其他合理平衡的树实现都很好 - 最好使用库中的一个而不是创建自己的树)。

一棵树应按文件中的位置排序。这使您可以执行log(n)查找以查看缓存是否存在。

另一棵树应该按照使用的时间排序(可以用每次使用时增加1的数字表示)。使用缓存块时,将其删除,更新时间并再次插入。这也将采用log(n)。当您错过时,删除树的最小元素,并将新块添加为最大。 (不要忘记同时删除/添加该块到文件中的位置树。)

如果您的缓存中没有很多项目,那么最好还是将所有内容存储在已排序的数组中(使用插入排序添加新元素)。将16个项目向下移动到数组中的一个位置非常快。