【问题标题】:some hashtable / unordered_map questions一些 hashtable / unordered_map 问题
【发布时间】:2013-10-30 06:02:55
【问题描述】:

我正在开发一个需要始终保持高效的低延迟应用程序。

我需要根据字符串查找一些索引,所以我使用的是 c++ unordered_map。 约束: - 只有插入和查找,没有删除 -key 是字符串,值是 int - 预计添加到 unordered_map 的条目不超过 100 万个

  • 我将 unordered_map 保留设置为 100 万,这是好还是应该保留比预期条目多 % 的顺序以避免重新散列? 我可以将其设置为 100 万,还是应该设置为接近 100 万或 2 次方的大素数。

  • 我在 c++ 标准库中使用默认字符串哈希函数,它恰好是 murmur2。 我的键介于 - 25 到 50 个字符之间,并且都是包含数字、大写英文字母和 _ 字符的唯一键。这个散列函数是否足以均匀分布密钥,还是我需要为 unordered_map 提供更好的散列函数?

  • unordered_map 是否会为 100 万个键、值对以及大小为 100 万的数组分配空间,当我调用保留或保留时,仅创建该大小的数组并动态分配键、值对插入时?

  • 插入时在堆上动态分配键、值对会有多大的阻力?特别是因为这是一个包含许多条目的大哈希表。

  • 出于性能原因,最好实现我自己的哈希表,并在堆栈上或初始化期间为 100 万个条目预分配内存,或者上述 unordered_map 的优化是否足够接近?

  • 有没有办法提前为 unorderd_map 中的预期条目数分配内存以避免插入时动态分配?

【问题讨论】:

    标签: c++ hashmap hashtable unordered-map low-latency


    【解决方案1】:

    让我们尝试用代码回答其中的一些问题。我没有粘贴整个东西,因为它有点长。请找到所有代码here。我在这里粘贴了部分输出:

    Map without reserve
    
            size: 0
    bucket_count: 23
     load_factor: 0
    
    Allocation count: 0
    
    ... 
    about 15 reallocations deleted 
    ...
    
    Allocation count: 1000015
    
            size: 1000000
    bucket_count: 1236397
     load_factor: 0.808802
    
    0: 550454
    1: 445645
    2: 180174
    3: 48593
    4: 9708
    5: 1568
    6: 231
    7: 22
    8: 2
    
    Map with reserve
    
            size: 0
    bucket_count: 23
     load_factor: 0
    
    Allocation count: 1
    
            size: 0
    bucket_count: 2144977
     load_factor: 0
    
    Allocation count: 1000000
    
            size: 1000000
    bucket_count: 2144977
     load_factor: 0.466205
    
    0: 1346008
    1: 626748
    2: 146625
    3: 22663
    4: 2669
    5: 248
    6: 15
    7: 1
    
    • 如您所见,当您为 1m 个元素保留空间时,只会发生一次分配。那是为了桶,我猜。
    • 保留的桶数远高于1m。
    • 分配的数量与插入的元素数量完全相同。
    • 您可以看到每种情况的哈希分布:有很多冲突。有时每个存储桶最多 8 个元素,即使有 50 万个存储桶是空的。
    • 如果没有初始 reserve,沿途大约有 15 次重新分配,但生成的地图有更少的桶。
    • 有了足够大的reserve,根本就没有重新分配。
    • 当然,您可以滚动自己的哈希表。例如,您可以为所有键保留一个连续的空间块,因为它们每个不超过 50 个字节,并且为值保留一个块。但我敢肯定,这将是一项相当大的工作,可能没有很好的好处。在您开始重新实现可能不需要的内容之前,分析并记录您的内存分配。

    【讨论】:

    • 如果我将负载因子设置为 1.0,存储桶应该等于保留条目,对吗?
    • 你能做到吗?我相信你只能更改max_load_factor,默认为1.0。
    • 对不起,我的意思是,当 max_load_factor 设置为 1.0(也是默认值)时,存储桶和元素计数应该相同吗?此外,当储备设置为 100 万个元素时,为相应数量的存储桶分配空间,还是为存储桶和元素(键、值)对分配空间?动态内存分配是编写低延迟应用程序的 NO 之一。
    • @Medicine,我查看了 GCC 的 unordered_map 实现,它将桶数乘以 _S_growth_factor(即 2)在 hashtable_policy.h 内,然后取大于提供的列表__prime_list 的结果。这就是2144977 的来源。
    • @Medicine,通过提供您自己的分配器,您可以控制内存分配操作。预先分配一个池桶节点并从那里分配是有意义的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 2016-03-28
    • 2023-04-04
    • 2019-04-12
    相关资源
    最近更新 更多