超高性能 C/C++ 哈希映射(表、字典)[关闭]

Posted

技术标签:

【中文标题】超高性能 C/C++ 哈希映射(表、字典)[关闭]【英文标题】:Super high performance C/C++ hash map (table, dictionary) [closed] 【发布时间】:2011-03-19 01:11:25 【问题描述】:

我需要将原始键(int,可能是 long)映射到高性能哈希映射数据结构中的结构值。

我的程序将有几百个这样的地图,每个地图通常最多有几千个条目。但是,地图会不断“刷新”或“搅动”;想象一下每秒处理数百万条adddelete 消息。

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

【问题讨论】:

您是否需要对数据进行按键搜索? 更新或检索会更频繁吗? (添加/删除,或读取/更新不改变密钥) @roe: 添加/删除操作比获取操作频繁(100 倍)。 四年半之后,知道什么最适合您的需求会很有趣。如果当前的答案都不令人满意,您可以自己编写并接受。 感谢您在 *** Mods 结束这样一个有用的问题 【参考方案1】:

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

【讨论】:

你能详细说明缺点是什么吗? IIRC,这是一个内存问题,当删除一个元素时,该元素被破坏但它的内存仍然存在(我猜是用作缓存)。 @Haywood Jablomey:主要缺点是它要求您分离一两个(如果您曾经删除元素)值并且永远不要使用它们。在某些情况下,这很容易做到,例如负整数或类似的,但在其他情况下并非如此。 今天你会接受这个建议吗?【参考方案2】:

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

【讨论】:

【参考方案3】:

我建议uthash。只需包含#include "uthash.h",然后在结构中添加UT_hash_handle,并在结构中选择一个或多个字段作为键。关于性能的一句话here。

【讨论】:

【参考方案4】:

如果您有一个多线程程序,您可以在intel thread building blocks library 中找到一些有用的哈希表。例如 tbb::concurrent_unordered_map 和 std::unordered_map 的 api 相同,但它的主要功能是线程安全的。

另外看看facebook的folly library,它有高性能并发hash table和skip list。

【讨论】:

【参考方案5】:

http://incise.org/hash-table-benchmarks.htmlgcc 有一个非常非常好的实现。但是,请注意,它必须尊重一个非常糟糕的标准决定:

如果发生 rehash,所有迭代器都将失效,但引用和 指向单个元素的指针仍然有效。如果没有实际的重新散列 发生,没有变化。

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

这基本上意味着标准规定实现必须基于链表。 它可以防止具有更好性能的开放寻址。

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

【讨论】:

另见this,它讨论了桶接口如何也需要链接。关于参考的观点非常好。很容易争论并说这是一个有用的保证,但在许多情况下,我们只希望引用避免再次查找元素,通常的原因是因为查找太慢......如果它没有的话就不会必须保持引用有效,因此可以使用开放寻址!所以这似乎有点鸡和蛋。 This 引用了 2003 年的提案,明确讨论了选择。【参考方案6】:

来自 android 资源(因此获得 Apache 2 许可)

https://github.com/CyanogenMod/android_system_core/tree/ics/libcutils

查看 hashmap.c,选择 include/cutils/hashmap.h,如果不需要线程安全,可以删除互斥代码,示例实现在 libcutils/str_parms.c 中

【讨论】:

【参考方案7】:

尝试来自Miscellaneous Container Templates 的哈希表。它的 closed_hash_map 与 Google 的 dense_hash_map 的速度差不多,但更易于使用(对包含的值没有限制)并且还有其他一些好处。

【讨论】:

【参考方案8】:

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

如果不是……

哈希映射似乎是您要求的明确答案。它提供基于键的 o(1) 查找。如今,大多数 STL 库都提供了某种散列。所以请使用您的平台提供的那个。

完成该部分后,您必须测试解决方案以查看默认散列算法在性能方面是否足以满足您的需求。

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

    很好的旧素数乘法算法 http://www.azillionmonkeys.com/qed/hash.html http://burtleburtle.net/bob/ http://code.google.com/p/google-sparsehash/

如果这还不够好,您可以自己滚动一个散列模块,它可以解决您在测试过的 STL 容器和上述散列算法之一中看到的问题。请务必在某处发布结果。

哦,有趣的是您有多个映射...也许您可以通过将密钥设置为 64 位 num 来简化,其中高位用于区分它属于哪个映射并将所有键值对添加到一个巨大的哈希中.我已经看到具有十万左右符号的散列在基本素数散列算法上运行得非常好。

与数百张地图相比,您可以检查该解决方案的性能。我认为从内存分析的角度来看这可能会更好...如果您确实要进行此练习,请在某处发布结果

我相信,除了散列算法之外,它还可能是不断添加/删除内存(可以避免吗?)以及可能对应用程序性能更重要的 CPU 缓存使用配置文件

祝你好运

【讨论】:

【参考方案9】:

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

【讨论】:

是的。 VS2013 的 std::unordered_map 占用了我整个执行时间的 90% 以上,尽管我只将地图用于相对较小的部分处理。【参考方案10】:

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

查看 LGPL 的 Judy arrays。从未使用过自己,但在少数情况下向我宣传。

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

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

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

这暗示您可能希望首先专注于改进算法。如果数据只写不读,那为什么还要写呢?

【讨论】:

以上是关于超高性能 C/C++ 哈希映射(表、字典)[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

字典和哈希表之间的真正区别是啥?

没有动态分配的哈希表/映射实现

哈希表——swift字典的实现原理

Python 映射类型:字典

python 字典为啥这么快

数据结构之哈希表