超高性能C / C ++哈希图(表,字典)


84

我需要将原始键(int,也许很长)映射为高性能哈希映射数据结构中的结构值。

我的程序将包含几百个这样的映射,每个映射通常最多具有数千个条目。但是,这些地图会不断“刷新”或“搅动”;想象处理数以百万计adddelete消息的第二。

C或C ++中的哪些库具有适合此用例的数据结构?或者,您如何建议自己建造?谢谢!


1
您是否需要通过键对数据进行搜索处理?
Guillaume Lebourgeois,2010年

3
更新或检索会更频繁吗?(添加/删除或不更改密钥的读取/更新)
falstro 2010年

stackoverflow.com/questions/266206/…。这可能是一个不错的起点。
DumbCoder 2010年

2
@roe:添加/删除操作比获取操作频繁(100倍)。
Haywood Jablomey 2010年

1
四年半后,知道最适合您的需求会很有趣。如果当前答案都不令人满意,您可以编写自己的答案并接受。
Walter Tross

Answers:


31

我建议您尝试使用Google SparseHash(或C11版本的Google SparseHash-c11),看看它是否满足您的需求。它们具有内存高效的实现以及针对速度进行了优化的实现。很久以前我做了一个基准测试,就速度而言,它是最好的哈希表实现(但是有缺点)。


16
您能否详细说明缺点是什么?
Haywood Jablomey 2010年

IIRC,这是一个内存问题,当删除一个元素时,该元素被破坏了,但它的内存仍然有效(我猜是用作缓存)。
Scharron

4
@Haywood Jablomey:主要缺点是它要求您拆分一个或两个(如果您曾经擦除过元素)值,并且永远不要使用它们。在某些情况下,这很容易做到,例如使用负整数或类似的方法,但在其他情况下则并非如此。
2010年

3
您今天支持这个建议吗?
einpoklum

11

C或C ++中的哪些库具有适合此用例的数据结构?或者,您如何建议自己建造?谢谢!

查看LGPL的Judy阵列。从未使用过自己,但有几次向我做广告。

您也可以尝试对STL容器进行基准测试(std :: hash_map等)。取决于平台/实现和源代码调整(尽可能多地预分配动态内存管理非常昂贵),它们可能会具有足够的性能。

另外,如果最终解决方案的性能胜过解决方案的成本,则可以尝试订购具有足够RAM的系统,以将所有内容放入普通阵列。按索引访问的性能无与伦比。

添加/删除操作比获取操作频繁(100x)。

这表明您可能想先集中精力改进算法。如果只写数据而不读数据,那为什么还要写数据呢?


11

只需默认使用boost::unordered_map(或其他tr1)即可。然后分析您的代码,看看该代码是否是瓶颈。只有这样,我才建议精确分析您的需求以找到更快的替代品。


15
它是。VS2013std::unordered_map占用了我整个执行时间的90%以上,即使我仅将地图用于一小部分处理。
卡梅隆2015年


4

喀什非常有效率。有作者的详细基准:https : //attractivechaos.wordpress.com/2008/10/07/another-look-at-my-old-benchmark/,它还显示khash击败了许多其他哈希库。



2

首先检查现有的解决方案(如libmemcache)是否适合您的需求。

如果不 ...

哈希图似乎是您要求的肯定答案。它基于键提供o(1)查找。如今,大多数STL库都提供某种哈希。因此,请使用您的平台提供的一种。

完成该部分后,您必须测试解决方案,以查看默认哈希算法是否足以满足您的需求。

如果不是,您应该探索网上找到的一些很好的快速哈希算法

  1. 好老素数乘算法
  2. http://www.azillionmonkeys.com/qed/hash.html
  3. http://burtleburtle.net/bob/
  4. http://code.google.com/p/google-sparsehash/

如果这还不够好,您可以自己滚动一个哈希模块,以解决您通过测试的STL容器以及上述哈希算法之一看到的问题。确保将结果发布到某处。

哦,它有多个映射,这很有趣...也许可以通过将密钥作为64位num来进行简化,其高位用于区分它属于哪个映射,并将所有密钥值对添加到一个巨型哈希中。我已经看到有数十万个符号的散列在基本质数散列算法上运行得很好。

您可以检查与数百张地图相比该解决方案的性能..我认为从内存配置文件的角度来看可能会更好...如果需要进行此练习,请务必将结果张贴在某处

我相信,除了哈希算法之外,它还可以是不断增加/删除内存(可以避免吗?)和cpu缓存使用情况配置文件,这些配置文件对于应用程序的性能可能更为关键。

祝好运


2

尝试使用其他容器模板中的哈希表。它closed_hash_map的速度与Google的速度大致相同dense_hash_map,但更易于使用(对包含的值没有限制),并且还具有其他优点。


2

我建议提塔什。只需在结构中#include "uthash.h"添加一个UT_hash_handle,然后在结构中选择一个或多个字段作为键即可。关于这里的表现。


1

http://incise.org/hash-table-benchmarks.html gcc具有非常好的实现。但是,请记住,它必须遵守一个非常糟糕的标准决定:

如果进行了重新哈希处理,则所有迭代器均无效,但是对单个元素的引用和指针仍然有效。如果没有发生实际的重新哈希处理,则不会进行任何更改。

http://www.cplusplus.com/reference/unordered_map/unordered_map/rehash/

这意味着基本上该标准说该实现必须基于链接列表。它会阻止具​​有更好性能的开放式寻址。

我认为google sparse使用的是开放式寻址,尽管在这些基准测试中,只有密集版本的性能优于竞争对手。但是,稀疏版本优于所有在内存使用方面的竞争。(它也没有任何平稳的纯线性wrt元素数)


1
另请参阅this,其中讨论了存储桶接口还如何需要链接。关于引用的观点非常好。争辩并说这是一个有用的保证很诱人,但是在许多情况下,我们只希望引用避免再次查找元素,并且通常的原因是查找太慢了……如果没有的话就不会这样必须保持引用有效,因此可以使用开放式寻址!因此,它看起来有点像鸡和鸡蛋。引用了2003年的提案,明确讨论了这一选择。
underscore_d
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.