如何在cpp中创建一个固定大小(以内存为单位)的哈希表

How to create a fixed size (in terms of memory) hash table in cpp?

本文关键字:内存 哈希表 为单位 一个 创建 cpp      更新时间:2023-10-16

我正在处理许多基于某些输入生成浮点的计算。如果我缓存这些数量,似乎可以优化相当多的重复调用。问题是,我不想缓存超过一定量的内存(即10GiB)。有没有一种方法可以在我定义哈希映射时定义它,或者在每次向映射中添加元素时动态测试它?

实现这一点的一种方法是实现LRU缓存("最近最少使用"),它可以让您始终修剪最长时间未引用的元素。对于某些使用模式,这优化了下一个所需项目仍在缓存中的概率。

设计LRU缓存曾经是一个常见的面试问题(也许现在仍然如此),因此有许多so答案等待找到。这个看起来相当完整。

但我不是这样做的。10GiB是大量的内存,你可以在这个空间里保留很多条目。如果您可以消除开销并保留两倍的缓存条目,那么牺牲LRU缓存的精度可能是值得的。消除开销还可以累积地为您节省足够的周期,以抵消使用非最佳缓存修剪策略所需的周期。无论如何,LRU可能不是您的问题的最佳选择。谁知道呢?

有了一个好的哈希函数和一个大的哈希表,您可以使用另一种策略:只需为每个哈希值保留一个条目。该解决方案的优点是几乎为零开销。不需要时间戳,甚至不需要存储桶列表指针。不需要通过链来跟踪条目是否在缓存中;第一个命中是要替换的条目或条目。在实践中,如果你的条目不是太大,那么你可以很容易地将可用的条目数量增加一倍。

对于稍微更精确的解决方案,您可以为每个哈希值保留两个条目,有点像简化的布谷鸟哈希。同样,没有存储开销(只要最终使用了每个哈希值),并且只需要稍微增加查找成本。(实际上很少,因为两个条目都应该在同一个内存缓存行中。)为了获得类似LRU的行为,在这个变体中,如果你找到的缓存条目是哈希值的第二个条目,你可以交换这两个条目。(事实上,在第一个条目不是你需要的条目之后,你交换了两个条目;然后你要么使用要么替换现在是第一个条目的条目。)

C++标准库没有非链式哈希表,但数据结构非常琐碎,几乎不需要库支持。该库可能具有有用的哈希支持。(请参阅boost.hash了解更多散列,如果您的密钥是std::pairstd::tuple,则特别有用。)

除此之外,您真正需要的只是一个键值对数组,它的大小可以根据您想要放入缓存的内存量而定。初始化这个数组有一个小问题:它需要初始化为一些东西,通常是默认的键和值构造函数产生的东西。但是,与默认密钥相对应的实际插槽要么需要具有正确的值(不太可能是默认值),要么需要更改为具有不同哈希值的不同密钥。

为每个条目存储一个时间戳,并关注哈希表的capacity,当它接近边界值时,刷新旧条目。