On Thu, Dec 29, 2005 at 06:51:29AM +0900, [email protected] wrote:
On Thu, 29 Dec 2005, Johannes F. wrote:
That’s where the ‘can be’ part comes in
The point is that symbols support quicker lookup by their nature.
Whether they are quicker in practice will depend on the
implementation. From the timings you give, it looks like symbol lookup
is implemented by converting the symbol to a string and doing string
lookup. Which is obviously not quicker
i never consider that as an impl - i bet your right though… time for me to
read the source.
I think :sym.hash uses the method definition from Kernel (inherited
through
Object) and :sym.eql?(:foo) would also reuse the existing definition.
[see C code at the bottom]
So there’s seemingly no reason for symbol hashing/comparison not to be
faster than for strings. The benchmarks you linked to, as well as Jim’s,
use relatively short strings, but one can exaggerate the effect:
>> Strings Filling
>> 5.800000 0.000000 5.800000 ( 6.302649)
>> Strings Fetching
>> 3.120000 0.010000 3.130000 ( 3.404679)
>>
>> Symbols Filling
>> 2.120000 0.000000 2.120000 ( 2.326393)
>> Symbols Fetching
>> 0.640000 0.000000 0.640000 ( 0.700178)
#!/usr/bin/env ruby
require ‘benchmark’
SIZE = 100
N = 10000
RUBY_VERSION # => “1.8.4”
def make_str_keys
(1…SIZE).collect { |i| “long key” * i}
end
def make_sym_keys(strs)
strs.collect { |s| s.intern }
end
def populate(keys)
result = {}
keys.each_with_index do |k, i|
result[k] = i
end
result
end
def fetch(keys, hash)
keys.each do |key| hash[key] end
end
strs = make_str_keys
syms = make_sym_keys(strs)
str_hash = populate(strs)
sym_hash = populate(syms)
puts “Strings Filling”
puts Benchmark.measure {
N.times do
populate(strs)
end
}
puts “Strings Fetching”
puts Benchmark.measure {
N.times do
fetch(strs, str_hash)
end
}
puts
puts “Symbols Filling”
puts Benchmark.measure {
N.times do
populate(syms)
end
}
puts “Symbols Fetching”
puts Benchmark.measure {
N.times do
fetch(syms, sym_hash)
end
}
rb_define_method(rb_mKernel, "hash", rb_obj_id, 0);
…
VALUE
rb_obj_id(VALUE obj)
{
if (SPECIAL_CONST_P(obj)) {
return LONG2NUM((long)obj);
}
return (VALUE)((long)obj|FIXNUM_FLAG);
}
rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1);
…
static VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
if (obj1 == obj2) return Qtrue;
return Qfalse;
}