【问题标题】:caching multiple key hash缓存多个密钥哈希
【发布时间】:2025-11-27 17:55:02
【问题描述】:

我想在我的项目中做一些缓存。

让我的API是int foo(int a, float b, float c, int d, char e)

现在在我的项目中,有很多对上述耗时 API 的调用,其中重复值 a、b、c、d 和 e。现在我想用这些参数作为键来存储这个函数的返回值。

假设我的调用顺序是

foo(23, 3.45, 4.5, 90, 'd') // returns 1000, so I need to store it in cache as (23,3.45, 4.5, 90, 'd')->1000

foo(30, 1.2, 3.5, 100, 'e') // returns 2000, so I need to store it in cache as (30, 1.2, 3.5, 100, 'e')->2000

foo(23, 3.45, 4.5, 90, 'd') // No need to call this API, I just check in my cache value associated with    
//(23, 3.45, 4.5, 90, 'd'), which is already stored as 1000

在 C++ 中实现上述最佳策略应该是什么?哪种数据结构最适合做缓存表?

【问题讨论】:

  • 你在 [c] 和 [c++] 上都标记了这个问题;您想要哪种语言的答案?
  • 没有 C/C++ 这样的东西。 C++ 解决方案或 C 解决方案将大不相同,并且可能彼此不兼容。如果您的目标是易用性,我建议使用 C++。

标签: c++ c caching data-structures stl


【解决方案1】:

一个要点:缓存很困难。

人们常常认为缓存可以解决他们所有的问题,但他们却忘记了它带来的问题。非托管缓存只不过是巨大的内存泄漏。两个值得注意的策略:

  • 大小限制:当缓存已满时,添加新条目会导致另一个条目被驱逐(因此您需要一个方案来决定何时驱逐一个条目)
  • 时间限制:条目在经过一定时间后被清除

通常,当我们听到缓存时,我们会想到 LRU(最近最少使用)缓存。这些缓存受大小限制,当缓存已满时,最近最少使用的条目将被逐出。 注意:可能会导致多线程争用,因为只读访问实际上意味着修改值

这样的缓存是根据两个元素实现的:

  • (键 -> 值)映射,使用树或哈希映射
  • 优先级列表,在节点内交错以提高效率

如果你走这条路,我建议使用 Boost.MultiIndex 库。有一个MRU implementation 的示例,与您的需求非常相似。

【讨论】:

    【解决方案2】:

    如果您可以使用 boost,请查看boost::unordered_map,否则您可以使用std::map。您必须提供函子来生成密钥。

    【讨论】:

      【解决方案3】:

      它并不总是有效,并且在某种程度上依赖于编译器,但您可以考虑使用函数属性。您可能感兴趣的是 constpure 属性。 热门也可能很有趣。

      【讨论】:

        【解决方案4】:

        好问题。你有几个选择。首先,将所有值放入一个结构体中:

        struct values
        {
           int a;
           float b;
            ...
        };
        
        1. 如果序列的其中一个值最具代表性,您可以使用std::map 将该代表性值映射到“桶”。比方说最有代表性的是float b

          std::map< float, std::list < std::pair< values, int> > >

          std::list 表示,并存储成对的值结构和结果值(本例中为int)。

        2. 声明从值到结果的映射int。为此,您应该允许 values 结构与地图中的其他结构进行比较,因此您必须编写 operator<()

         int operator<(values const& left, values const& right)
         {
            if (left.a < left.b) ... // compare two values objects
         }
        

        然后像往常一样声明地图:

        std::map<values, int>
        

        还有一些其他的问题,比如拷贝构造函数等你要处理,不过思路是这样的。

        最后,您也可以将std::map 替换为unordered_map

        【讨论】:

          【解决方案5】:

          将它们全部放在一个结构中

          struct mykey{ int a; float b; float c; int d; char e; };
          

          然后将它们写入并散列结构,并将其用作键

          int foo(int a, float b, float c, int d, char e)
          {
              mykey tk = { a, b, c, d, e };
              guid key = md5( &tk, sizeof( tk ) );
          

          【讨论】:

            【解决方案6】:

            我会使用嵌套地图,因此您使用第一个参数从地图中查找地图,直到您使用最后一个参数查找的最终地图,结果是之前缓存的 foo 值。

            当你到达最后一个map,发现这个参数的设置没有调用foo,你只需要存储最后一个参数的foo的结果。

            【讨论】:

            • 效率低下:内存分散在各处,涉及多次查找。关于log(N) 的一件事是6*log(N) == log(N**6) &gt;&gt; log(6*N)(表示N 优于1)。
            【解决方案7】:

            我建议使用Hash table。您只需要计算数据的哈希函数。如果哈希足够强,则可以存储它并输出值,而无需存储参数。此外,这个方法应该比使用 std::map 更快。

            在 C++ 中,这可以用 unordered_map 或 std::hash_map 来实现。 使用非常简单的哈希函数就足够了,例如The String hash function

            顺便说一句,为参数存储输出值的方法称为Memoization

            【讨论】:

              最近更新 更多