-
-
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) |
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]
endDisclaimer: I haven't run that code, since I haven't installed ruby 2.0 on this machine yet.
@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.
Benchmark options hashes versus keyword arguments in Ruby 2.0.0-p0.
tl;dr:
**kwargsparameter is significantly slower than options hashes in Ruby 2 (Boo!)