gcc std::unordered_map 实现速度慢吗?如果是这样 - 为什么?

2024-02-13

我们正在用 C++ 开发高性能关键软件。我们需要一个并发哈希映射并实现它。因此,我们编写了一个基准测试来弄清楚,我们的并发哈希映射与std::unordered_map.

But, std::unordered_map似乎非常慢...所以这是我们的微基准测试(对于并发映射,我们生成了一个新线程以确保锁定不会被优化掉,并注意我从不插入 0 因为我也用google::dense_hash_map,需要一个空值):

boost::random::mt19937 rng;
boost::random::uniform_int_distribution<> dist(std::numeric_limits<uint64_t>::min(), std::numeric_limits<uint64_t>::max());
std::vector<uint64_t> vec(SIZE);
for (int i = 0; i < SIZE; ++i) {
    uint64_t val = 0;
    while (val == 0) {
        val = dist(rng);
    }
    vec[i] = val;
}
std::unordered_map<int, long double> map;
auto begin = std::chrono::high_resolution_clock::now();
for (int i = 0; i < SIZE; ++i) {
    map[vec[i]] = 0.0;
}
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
std::cout << "inserts: " << elapsed.count() << std::endl;
std::random_shuffle(vec.begin(), vec.end());
begin = std::chrono::high_resolution_clock::now();
long double val;
for (int i = 0; i < SIZE; ++i) {
    val = map[vec[i]];
}
end = std::chrono::high_resolution_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
std::cout << "get: " << elapsed.count() << std::endl;

(编辑:整个源代码可以在这里找到:http://pastebin.com/vPqf7eya http://pastebin.com/vPqf7eya)

结果为std::unordered_map is:

inserts: 35126
get    : 2959

For google::dense_map:

inserts: 3653
get    : 816

对于我们手动支持的并发映射(它执行锁定,尽管基准测试是单线程的 - 但在单独的生成线程中):

inserts: 5213
get    : 2594

如果我在没有 pthread 支持的情况下编译基准程序并在主线程中运行所有内容,我会得到以下手动支持并发映射的结果:

inserts: 4441
get    : 1180

我使用以下命令进行编译:

g++-4.7 -O3 -DNDEBUG -I/tmp/benchmap/sparsehash-2.0.2/src/ -std=c++11 -pthread main.cc

所以特别插入std::unordered_map似乎非常昂贵 - 35 秒,而其他地图则为 3-5 秒。而且查找时间似乎相当长。

我的问题:这是为什么?我在 stackoverflow 上读到另一个问题,有人问,为什么std::tr1::unordered_map比他自己的实现慢。评分最高的答案指出,std::tr1::unordered_map需要实现更复杂的接口。但我看不到这个论点:我们在并发映射中使用存储桶方法,std::unordered_map也使用桶方法(google::dense_hash_map不,但比std::unordered_map应该至少和我们手工支持的并发安全版本一样快?)。除此之外,我在界面中看不到任何强制执行使哈希映射表现不佳的功能的内容......

所以我的问题是:这是真的吗std::unordered_map好像很慢?如果不是:出了什么问题?如果是:原因是什么?

我的主要问题是:为什么将一个值插入到std::unordered_map如此昂贵(即使我们在开始时保留足够的空间,它的性能也好不到哪里去 - 所以重新散列似乎不是问题)?

EDIT:

首先:是的,所提供的基准测试并不是完美无缺的 - 这是因为我们用它进行了很多尝试,它只是一个黑客(例如uint64生成整数的分布实际上不是一个好主意,在循环中排除 0 有点愚蠢等等...)。

目前大多数评论都解释说,我可以通过为其预先分配足够的空间来使 unordered_map 更快。在我们的应用程序中,这是不可能的:我们正在开发一个数据库管理系统,需要一个哈希映射来存储事务期间的一些数据(例如锁定信息)。因此,该映射可以是从 1(用户仅进行一次插入并提交)到数十亿个条目(如果发生全表扫描)的所有内容。这里不可能预先分配足够的空间(并且一开始就分配大量空间会消耗太多内存)。

此外,我很抱歉,我没有足够清楚地说明我的问题:我对让 unordered_map 快速运行并不真正感兴趣(使用谷歌密集哈希映射对我们来说效果很好),我只是不太明白这种巨大的性能差异来自哪里。它不能只是预分配(即使有足够的预分配内存,密集映射也比 unordered_map 快一个数量级,我们手工支持的并发映射以大小为 64 的数组开始 - 因此比 unordered_map 小)。

那么到底是什么原因导致了这种糟糕的表现呢?std::unordered_map?或者以不同的方式问:有人可以编写一个实现吗std::unordered_map符合标准并且(几乎)与谷歌密集哈希图一样快的接口?或者标准中是否有某些内容强制实施者选择一种低效的方式来实施它?

EDIT 2:

通过分析,我发现大量时间用于整数除法。std::unordered_map使用素数作为数组大小,而其他实现则使用 2 的幂。为什么std::unordered_map使用质数?如果哈希值不好,要表现得更好吗?对于好的哈希值来说,恕我直言,这没有什么区别。

EDIT 3:

这些数字是std::map:

inserts: 16462
get    : 16978

Sooooooo:为什么插入到std::map比插入更快std::unordered_map...我的意思是WAT?std::map具有更差的局部性(树与数组),需要进行更多分配(每次插入与每次重新散列+每次碰撞加上〜1),并且最重要的是:具有另一种算法复杂性(O(logn)与O(1))!


我找到原因了:是gcc-4.7的问题!!

With gcc-4.7

inserts: 37728
get    : 2985

With gcc-4.6

inserts: 2531
get    : 1565

So std::unordered_mapgcc-4.7 中的版本已损坏(或者我的安装,这是 Ubuntu 上的 gcc-4.7.0 安装 - 另一个安装是 debian 测试上的 gcc 4.7.1)。

我将提交错误报告..在那之前:请勿使用std::unordered_map与海湾合作委员会4.7!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

gcc std::unordered_map 实现速度慢吗?如果是这样 - 为什么? 的相关文章

随机推荐

  • 如何“深度”克隆闭源第三方类的属性?

    The ICloneable http msdn microsoft com en us library system icloneable v vs 100 aspx NET框架的接口通常提供一种方法来支持cloning http en
  • 当特定部分出现在屏幕上时切换类[重复]

    这个问题在这里已经有答案了 我正在制作一个大滚动页 我的导航是固定位置的 当导航到达我页面上的特定部分时 我想更改导航上的颜色 从黑色到白色 反之亦然 因为有些是白色的 有些是黑色的 我想做一个对比 我已经在 css 中创建了一个应该切换的
  • Chef 客户和验证者

    我试图理解 Chef 客户端和验证器的概念 以及它们与引导过程的关系 根据本文 http docs opscode com server manage clients html 厨师 客户将使用 etc chef validation pe
  • 为什么 isNaN('') 或 isNaN("") 为 false(单引号或双引号被视为有效数字)?

    我需要一个内置函数来检查变量是否包含 Javascript 中的有效数字 如下这个链接 https stackoverflow com questions 175739 built in way in javascript to check
  • TabLayout重心不起作用

    我有一个 TabLayout 我希望选项卡显示在屏幕中央 下面是我的 TabLayout 的 XML
  • 如何在 gulp 任务中运行 shell 命令并检测它何时完成?

    我正在尝试使用以下命令在 gulp 任务中运行 shell 命令child process spawn 我必须检测任务何时完成运行 所以我正在使用stdout检查我在命令末尾发出的特定字符串 但由于某种原因 它看起来不像我的字符串正在发出
  • 如何在 XSLT 中调用点网程序集/命名空间

    我正在 XSLT 中编写点网代码 当我调用任何名称空间或在 XSLT 中写入 using 指令时 它会给出以下错误 错误 无法识别 com myassemble 是否可以在 xslt 中使用任何程序集 这是可能的 并且您需要使用扩展对象 h
  • TCPDF 将底部边距设置为零

    我正在 php 中使用 TCPDF 创建 pdf 我需要将我的数据包含到没有下边距的 pdf 中 数据将包含在页面末尾 pdf gt SetLeftMargin 14 pdf gt SetTopMargin 6 pdf gt SetFont
  • super() 和显式 super(Cl,self) (带有 __slots__ 和 attrs)有什么区别

    我正在使用attrspython 包 结合继承和槽 我想从派生方法中调用父类的方法 该问题演示如下 import attr attr s slots True class Base def meth self print hello att
  • javascript:获取函数中传递的实际参数的名称

    我们能知道函数中传递的实际参数的名称吗 喜欢 func a b c d 当我们调用它时 我希望在输出中打印 a b c d 就像我将 func 定义为 function func e f g h do something here so t
  • DataAnnotation 正则表达式对于文件输入始终返回 false

    我已经尝试了很多正则表达式RegularExpression数据注释来检查文件扩展名是否是图像 并且它总是返回 false 例如我也尝试过FileExtension属性 但它会在 jquery validation 上产生错误 我正在使用
  • 读取输入后无法写入输出

    我正在编写一个连接到 servlet 的程序 这要归功于HttpURLConnection但我在检查网址时卡住了 public void connect String method throws Exception server HttpU
  • Android 关闭自定义对话框

    我正在尝试让自定义对话框在按下按钮时关闭 set up dialog Dialog dialog new Dialog BrowseActivity this dialog setContentView R layout about dia
  • 使 Eclipse 出现错误时不运行项目

    是否可以使 Eclipse Helios SR2 在出现错误时不运行您的项目 而不是提示答案或无论如何运行 设想 在 Eclipse 中 我点击了 运行 按钮 有编译错误 Eclipse 询问我是否仍要继续运行 我有 是 和 否 两个选项
  • 标签“bg”不存在

    这是我的标签代码 from Tkinter import Tk BOTH Canvas Text END import Tkinter as tk from ttk import Frame Button Style Label Entry
  • SUMIF 单元格不是公式

    我正在尝试创建一个 Excel 电子表格 其中包含公司每位员工的一行 其中每列引用他们每周的工作时间 最初 单元格中填充的是另一张工作表中的预期每周工作小时数 但随后会手动替换为人们每周实际工作的小时数 我希望能够对人们实际工作的小时数进行
  • Web 共享 API 级别 2 PDF 支持

    我正在为我的 PWA 应用程序使用网络共享级别 2 除了 PDF 之外 所有媒体格式都可以正常工作 Web api 返回 PDF 的 base64 字符串 在客户端 我正在从中创建 blob 对象 但是当我分享它时 抛出异常 权限被拒绝 v
  • 没有 .NET 的 Windows 身份验证标头。可能的?

    我想知道是否有人知道一种无需托管在 ASP 站点上即可使用 Windows 身份验证的方法 这是一个可以访问 LDAP 的 Intranet 所以我想知道是否有办法强制客户端向我提供数据 就好像数据来自 ASP 站点一样 我只需要登录域和用
  • 重新排序 Django 模型中的字段

    我想向 django 应用程序中的每个模型添加一些字段 这次是created at updated at and notes 为 20 多个模型中的每一个模型重复代码似乎很愚蠢 因此 我决定使用抽象基类来添加这些字段 问题是从抽象基类继承的
  • gcc std::unordered_map 实现速度慢吗?如果是这样 - 为什么?

    我们正在用 C 开发高性能关键软件 我们需要一个并发哈希映射并实现它 因此 我们编写了一个基准测试来弄清楚 我们的并发哈希映射与std unordered map But std unordered map似乎非常慢 所以这是我们的微基准测