Skip to content

Instantly share code, notes, and snippets.

@lsegal
Last active December 14, 2015 07:59
Show Gist options
  • Select an option

  • Save lsegal/5054968 to your computer and use it in GitHub Desktop.

Select an option

Save lsegal/5054968 to your computer and use it in GitHub Desktop.
require 'benchmark'
class Foo
def optshash opts={}; [opts[:a], opts[:b]] end
def anykwargs **kw; [kw[:a], kw[:b]] end
def specific_kwargs(a:1, b:2) [a, b] end
end
TIMES = 1_000_000
foo = Foo.new
Benchmark.bmbm do |r|
r.report("optshash") { TIMES.times { foo.optshash a: 1, b: 2 } }
r.report("anykwargs") { TIMES.times { foo.anykwargs a: 1, b: 2 } }
r.report("specific_kwargs") { TIMES.times { foo.specific_kwargs a: 1, b: 2 } }
end
__END__
(using ruby2.0.0-p0):
Rehearsal ---------------------------------------------------
optshash 0.940000 0.000000 0.940000 ( 0.943659)
anykwargs 1.440000 0.010000 1.450000 ( 1.446052)
specific_kwargs 1.740000 0.000000 1.740000 ( 1.746192)
------------------------------------------ total: 4.130000sec
user system total real
optshash 0.920000 0.000000 0.920000 ( 0.917351)
anykwargs 1.440000 0.010000 1.450000 ( 1.443314)
specific_kwargs 1.740000 0.010000 1.750000 ( 1.749727)
[Finished in 8.4s]
(using a modified version of this benchmark in 1.9.3, optshash only):
~/Desktop$ rvm 1.9.3 do ruby vm.rb
Rehearsal --------------------------------------------
optshash 1.030000 0.000000 1.030000 ( 1.035424)
----------------------------------- total: 1.030000sec
user system total real
optshash 1.030000 0.010000 1.040000 ( 1.035779)
@lsegal
Copy link
Copy Markdown
Author

lsegal commented Feb 28, 2013

Benchmark options hashes versus keyword arguments in Ruby 2.0.0-p0.

tl;dr:

  1. Options hashes are faster in Ruby 2 than in Ruby 1.9.3 (Yay!)
  2. Using a **kwargs parameter is significantly slower than options hashes in Ruby 2 (Boo!)
  3. Using specific keyword names (a: 1, b: 2) is even slower-- almost 2x slower than using an options hash. (What!?)
  4. Finally, keyword arguments in Ruby 2 are also significantly slower than using options hashes in 1.9.3

@cwalsh
Copy link
Copy Markdown

cwalsh commented Feb 28, 2013

That's interesting, but it's not really a fair test because they aren't all doing the same thing. The first method (optshash) takes a hash with any number of unchecked keys and makes no use of default values for those keys. To compare similar functionality, you'd need to benchmark merging the arguments with a default options hash, or comparing the contents with default expected values.

e.g.

def optshash2 opts={}
  opts = {a: 1, b: 2}.merge(opts)
  [opts[:a], opts[:b]] 
end
# or perhaps...
def optshash3 opts={}
  [opts[:a] || 1, opts[:b] || 2] 
end

Disclaimer: I haven't run that code, since I haven't installed ruby 2.0 on this machine yet.

@lsegal
Copy link
Copy Markdown
Author

lsegal commented Mar 5, 2013

@cwalsh: your point is noted for the "specific_kwargs" test, but not optshash vs kwargs-- that one does not provide defaults. The point to this benchmark is that using kwargs instead of opts={} provides you no benefit. The specific_kwargs is only added in for its interesting performance characteristics, namely that assigning locals from a hash is somehow slower than grabbing the values from a hash directly.

That said, the numbers for your implementations are:

Rehearsal ---------------------------------------------------
optshash          0.910000   0.000000   0.910000 (  0.913547)
optshash2         3.140000   0.020000   3.160000 (  3.164225)
optshash3         0.910000   0.000000   0.910000 (  0.912037)
anykwargs         1.350000   0.010000   1.360000 (  1.361221)
specific_kwargs   1.660000   0.010000   1.670000 (  1.660602)
------------------------------------------ total: 8.010000sec

                      user     system      total        real
optshash          0.880000   0.000000   0.880000 (  0.878799)
optshash2         3.140000   0.020000   3.160000 (  3.164354)
optshash3         0.920000   0.010000   0.930000 (  0.925604)
anykwargs         1.350000   0.010000   1.360000 (  1.359308)
specific_kwargs   1.630000   0.010000   1.640000 (  1.646637)

So merge is the real killer, but that's pretty much expected. optshash3 is probably closer to how Ruby's internal named args works, and it's still faster.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment