Dynamic method calling in Ruby

后端 未结 5 740

As far as I am aware there are three ways to dynamically call a method in Ruby:

Method 1:

s = SomeObject.new
method = s.method(:dynamic_method)
metho         


        
5条回答
  •  独厮守ぢ
    2020-12-12 20:00

    Here is all possible method calls:

    require 'benchmark/ips'
    
    class FooBar
      def name; end
    end
    
    el = FooBar.new
    
    Benchmark.ips do |x|
      x.report('plain') { el.name }
      x.report('eval') { eval('el.name') }
      x.report('method call') { el.method(:name).call }
      x.report('send sym') { el.send(:name) }
      x.report('send str') { el.send('name') }
      x.compare!
    end
    

    And results are:

    Warming up --------------------------------------
                   plain   236.448k i/100ms
                    eval    20.743k i/100ms
             method call   131.408k i/100ms
                send sym   205.491k i/100ms
                send str   168.137k i/100ms
    Calculating -------------------------------------
                   plain      9.150M (± 6.5%) i/s -     45.634M in   5.009566s
                    eval    232.303k (± 5.4%) i/s -      1.162M in   5.015430s
             method call      2.602M (± 4.5%) i/s -     13.009M in   5.010535s
                send sym      6.729M (± 8.6%) i/s -     33.495M in   5.016481s
                send str      4.027M (± 5.7%) i/s -     20.176M in   5.027409s
    
    Comparison:
                   plain:  9149514.0 i/s
                send sym:  6729490.1 i/s - 1.36x  slower
                send str:  4026672.4 i/s - 2.27x  slower
             method call:  2601777.5 i/s - 3.52x  slower
                    eval:   232302.6 i/s - 39.39x  slower
    

    It's expected that plain call is the fastest, no any additional allocations, symbol lookups, just lookup and evaluation of method.

    As for send via symbol, it is faster than via string as its much more easer to allocate memory for symbol. Once it's defined it's stored for long term in memory and there no reallocations.

    The same reason can be said about method(:name) (1) it's requires to allocate memory for Proc object (2) we are calling the method in class which leads for additional method lookup which takes time too.

    eval is runs interpreter so it's the heaviest.

提交回复
热议问题