在哈希查找中,符号如何比字符串更快?

Asa*_*svi 2 ruby hash symbols hashmap

我理解为什么应该使用符号而不是哈希中的字符串的一方面。也就是说,内存中只有一个给定 Symbol 的实例,而给定 String 可能有多个具有相同值的实例。

我不明白的是,在哈希查找中,符号如何比字符串快。我看过这里的答案,但我仍然不太明白。

如果:foo.hash == :foo.object_id返回true,那么它会有意义,因为这样它就可以使用对象 id 作为哈希值,而不必每次都计算它。然而,情况并非如此,:foo.object_id也不等于:foo.hash. 因此我的困惑。

tad*_*man 7

没有义务hash等于object_id。这两件事用于完全不同的目的。重点hash是尽可能具有确定性和随机性,以便您插入到哈希中的值均匀分布。重点object_id是定义一个唯一的对象标识符,尽管不要求它们是随机的或均匀分布的。事实上,随机化它们会适得其反,只会无缘无故地使事情变慢。

符号往往更快的原因是因为它们的内存被分配一次(垃圾收集问题除外)并为同一符号的所有实例回收。字符串不是那样的。它们可以通过多种方式构建,甚至两个字节对字节相同的字符串也可能是不同的对象。事实上,除非您确定它们是同一个对象,否则假设它们比其他情况更安全。

现在在计算时hash,即使字符串变化很小,值也必须随机不同。由于符号不能改变计算,因此可以进行更多优化。例如,您可以只计算 的散列,object_id因为它不会改变,例如,而字符串需要考虑其本身的内容,这可能是动态的。

尝试对事物进行基准测试:

require 'benchmark'

count = 100000000

Benchmark.bm do |bm|
  bm.report('Symbol:') do
    count.times { :symbol.hash }
  end
  bm.report('String:') do
    count.times { "string".hash }
  end
end
Run Code Online (Sandbox Code Playgroud)

这给了我这样的结果:

       user     system      total        real
Symbol:  6.340000   0.020000   6.360000 (  6.420563)
String: 11.380000   0.040000  11.420000 ( 11.454172)
Run Code Online (Sandbox Code Playgroud)

在这种最微不足道的情况下,这很容易快 2 倍。基于一些基本测试,随着字符串变长但符号时间保持不变,字符串代码的性能降低了O(N)