【问题标题】:When does it make sense to presize a hash?什么时候对哈希进行预置大小有意义?
【发布时间】:2011-10-23 08:22:00
【问题描述】:

来自perldata

You can preallocate space for a hash by assigning to the keys() function.
This rounds up the allocated buckets to the next power of two:

   keys(%users) = 1000;      # allocate 1024 buckets

是否有一个经验法则可以说明何时调整哈希值会提高性能?

【问题讨论】:

    标签: perl hash


    【解决方案1】:

    经验法则是,您知道的哈希值越大,您就越有可能从预先调整大小中获得价值。考虑一下,如果您的哈希有 10 个插槽,并且您开始一个接一个地添加,那么扩展的数量将 a)很少(如果有的话),并且 b)很小(因为数据很少)。

    但如果您知道您将需要至少 100 万个项目,那么就没有理由扩展,并在表增长时一遍又一遍地复制底层和不断扩展的数据结构。

    你会注意到这个扩展吗?嗯,也许吧。现代机器非常快,它可能不会出现。但这是堆扩展的大好机会,因此会导致 GC 和各种事情的级联。所以,如果你知道你会使用它,这是一个“便宜”的修复,可以调整更多的性能。

    【讨论】:

      【解决方案2】:

      我尝试对哈希增长的扩展成本进行基准测试:

      use Benchmark qw(cmpthese);
      
      # few values
      cmpthese(-4, {
          prealloc => sub {
              my %hash;
              keys(%hash) = 17576;
              $hash{$_} = $_ for 'aaa' .. 'zzz';
          },
          normal   => sub {
              my %hash;
              $hash{$_} = $_ for 'aaa' .. 'zzz';
          },
      });
      
      # more values
      cmpthese(-8, {
          prealloc => sub {
              my %hash;
              keys(%hash) = 456976;
              $hash{$_} = $_ for 'aaaa' .. 'zzzz';
          },
          normal   => sub {
              my %hash;
              $hash{$_} = $_ for 'aaaa' .. 'zzzz';
          },
      });
      

      结果听起来不像是大优化,但是 Will Hartung 提到的减少堆碎片可能会有所帮助。在 WinXP 机器上运行 perl 5.12。

             Rate   normal prealloc
      normal   48.3/s       --      -2%
      prealloc 49.4/s       2%       --
              (warning: too few iterations for a reliable count)
           s/iter   normal prealloc
      normal     3.62       --      -1%
      prealloc   3.57       1%       --
      

      【讨论】:

        【解决方案3】:

        基本上它是优化哈希性能的大门。哈希性能在很大程度上取决于使用的哈希算法和您正在处理的数据,因此几乎不可能提出经验法则。反正有话可以说。

        您知道,每种数据结构都在空间和时间效率之间提供给定的平衡。哈希表在时间效率方面特别出色,提供了吸引人的恒定 (0(1)) 时间访问。

        除非发生碰撞,否则这适用。当发生碰撞时,访问时间与碰撞值对应的桶大小成线性关系。 (查看this 了解更多详情)。冲突除了“更慢”之外,主要是对访问时间保证的破坏,这是最重要的一个方面,通常会导致首先选择哈希表。

        理想情况下,哈希表可以针对所谓的“完美哈希”(这实际上只有当您可以将算法微调到您将处理的数据类型时才可行),但这并不容易实现在一般情况下(实际上这是一种委婉说法)。无论如何,事实上更大的哈希表(连同良好的哈希算法)可以降低冲突的频率,从而提高性能,但会以内存为代价。较小的哈希表会出现更多的冲突(因此性能较差,访问时间保证质量较差),但占用的内存较少。

        因此,如果您分析您的程序并发现哈希表访问是一个瓶颈(出于任何原因),您就有机会通过为哈希空间保留更多内存来解决这个问题(如果您有内存可以提供)。

        在任何情况下,我都不会随机增加这个值,而是在彻底分析之后,因为 perl 使用的算法也是在(AFAIK)中编译的,这对哈希性能也有很大影响(在换句话说,即使你将哈希空间变大,你也可能会发生很多冲突)。

        像往常一样,与性能相关的东西,它可能有用与否,这取决于你的具体情况。

        【讨论】:

          猜你喜欢
          • 2011-02-07
          • 2016-07-11
          • 1970-01-01
          • 1970-01-01
          • 2011-01-21
          • 1970-01-01
          • 1970-01-01
          • 2011-01-09
          相关资源
          最近更新 更多