skip to main | skip to sidebar

Wednesday, August 30, 2006

Binding and Benchmarking (or, What I Did for Lunch)

Today, Kent Sibilev posted a neat little trick over on his blog (which I was reading while I ate my lunch). His code allows you to replace code like this:


class Simple
 def initialize(foo, bar, baz)
 @foo = foo
 @bar = bar
 @baz = baz
 end
end

with code like this:

class Bound
 def initialize(foo, bar, baz)
 binding.local_to_instance
 end
end

This looks like a great time saver — at first blush (Kent does warn that it's not effecient). I tried it in a small script and it worked great. I can see myself doing this a lot in simple scripts, but will it work for a program that instantiates a lot of objects? Only you and your code know for sure, but I pulled out the Benchmark to see what it thought.

My first step was to wrap up the two versions of the class above, with some instantiating code in a benchmarking script like this:


class Binding
 def local_to_instance
 eval("local_variables").each do |name|
 eval("self").instance_variable_set("@#{name}", eval(name))
 end
 end
 
 alias :kernel_eval :eval
 def eval(code)
 kernel_eval(code, self)
 end
end
class Bound
 attr_accessor :foo, :bar, :baz
 
 def initialize(foo, bar, baz)
 binding.local_to_instance
 end
end
class Simple
 attr_accessor :foo, :bar, :baz
 
 def initialize(foo, bar, baz)
 @foo = foo
 @bar = bar
 @baz = baz
 end
end
require 'benchmark'
Benchmark.bmbm(10) do |x|
 x.report('simple') do
 for i in 1..100_000 do
 a = Simple.new(1,2,3)
 end
 end
 x.report('bound') do
 for i in 1..100_000 do
 a = Bound.new(1,2,3)
 end
 end 
end

Note: Kent's Binding class (which does all the magic) is up there in the code.

If you're not used to the Benchmark library, all I'm doing is setting up a 'benchmark with rehearsal' test (the whole test will run twice to provide cleaner results), with a couple of labels for the report.

Running the code above produces a report like this:


Rehearsal ---------------------------------------------
simple 0.400000 0.000000 0.400000 ( 0.398161)
bound 2.620000 0.010000 2.630000 ( 2.662697)
------------------------------------ total: 3.030000sec
 user system total real
simple 0.140000 0.000000 0.140000 ( 0.137859)
bound 2.520000 0.010000 2.530000 ( 2.525122)

so, what does this prove? Well, Kent is right, his binding implementation isn't very effecient. On the other hand, it ripped through 100,000 instantiations of Bound objects in just two and a half seconds. I don't think that's liable to raise too many performance concerns. Maybe if you're creating tens of millions of objects it will start to get to you — or, maybe not. Try it. If it's too slow, profile it. If it's a problem, you can always go back to doing things the old fashioned way.

Posted by gnupate

No comments:

Post a Comment

Subscribe to: Post Comments (Atom)
 

AltStyle によって変換されたページ (->オリジナル) /