繁体   English   中英

有效地重用 std::unordered_map

[英]reusing std::unordered_map efficiently

我在我的程序中管理相对较小的临时字典。 我的问题:重用它们(使用后使用mymap.clear() )比delete旧的并创建new的更有效吗?

此外,这些字典目前实现为std::unordered_map<std::string, int> 这是有效的,但如果(根据上述使用模式)另一个容器( stl或不是)更可取,我会毫不犹豫地切换此实现。

你配置了吗? 因为现在这只是很多猜测。

考虑std::unordered_map上的newdelete只是增加了实例化/拆除容器本身的开销。 std::unordered_map::clear内部仍然会在它持有的每个对象上调用delete ,以便调用它的析构函数。 可能涉及到一个奇特的分配器,它为容器元素实现了一个相同大小的槽池,以节省内存管理开销。

根据所包含对象的复杂性,使用普通的std::vector可能更明智,也可能更明智

你必须分析你的开销在哪里。 但更重要的是,只有完成工作,如果这是你的程序的一部分,导致统计上显着放缓。 您应该选择易于阅读和实现清晰而不是微优化。

不幸的是, .clear()没有任何性能优势,重用只是获得一个新的基于节点的容器,它的工作量几乎相同。

如果您知道字典的最大大小,并且它相当小,请考虑为节点使用自定义分配器。

这样,您可能会使事情变得更紧凑并节省分配开销。

除此之外,避免在标准库之外分配数千个单独节点的其他容器也是可能的。

这是可行的,但如果(根据上述使用模式)另一个容器(stl 或不是)更可取,我会毫不犹豫地切换此实现。

好的选择开始。 如果你想尝试别的东西:

  • 考虑前缀树
  • 考虑来自其他库的其他哈希映射,例如abseil

使用真实数据衡量真实场景中的性能,以查看替代方案是否值得使用。

至少对于 GCC, std::unordered_map<std::string, int>在任何时间点都有如下动态分配:

  • 1 个存储桶数组的分配,每个存储桶将迭代器(可能实现为指针)保存到一个单向链接的节点列表中(通常在您的峰值元素数的 1 倍到 2 倍之间),或者当没有元素散列到该存储桶时的哨兵迭代器状态
  • #elements 分配:有一个带有 next 指针的节点,一个哈希值(是的,它保存了它!),以及std::stringint数据
  • #keys 长于 15:任何std::string对于短字符串优化(文本内容直接存储在std::string对象中)来说太长,将有一个指向动态分配的文本缓冲区的指针

当您执行.clear() ,后两类分配将被释放。 当容器本身被破坏时,只完成一次额外的释放。

所以,我不希望保留unordered_map很大的性能改进。

如果您关心性能,请更仔细地查看您的数据。 字符串长度有上限吗? 如果有并且它不是很大(例如 8 或 16 字节),您可以使用开放寻址又名封闭散列获取一个哈希表,其中键和值直接存储在存储桶中,因此只有一个动态分配正在进行。 这可能会给你带来很大的性能提升(但总是衡量)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM