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.
No comments:
Post a Comment