42
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rubyのdefine_method、class_evalで動的に定義されたメソッドの呼出コストを調べてみた

Posted at

はじめに

Rubyでは、通常のメソッド定義のほかに、動的にメソッドを定義する方法がいくつかありますが、
動的に定義されたメソッドと通常のメソッドの呼出コストの差が気になります。

また、動的に定義されたメソッドの中でもdefine_methodで定義されたものは重いということもよく知られています。
一例として、Railsでは、重いdefine_methodを使う代わりに文字列のclass_evalを使用している箇所が多くあります。

というわけで、

  • 通常のメソッド定義
  • define_method
  • class_eval + 文字列
  • class_eval + ブロック

で定義したメソッドの呼出コストのベンチマークを取ってみました。

class_eval + ブロックは 正確には動的ではない(メソッドの内容を動的に変更できない)のですが、気になったので同時にベンチマークすることにしました。

ベンチマーク

環境

Ruby 2.1.2

コード

何もしないメソッドをそれぞれの方法で定義し、10000000回呼び出しています。

コード
require 'benchmark'

class Test

  # 通常のメソッド
  def test_normal
  end
  
  # define_method
  define_method :test_define_method do
  end

  # class_eval (文字列)
  class_eval <<-EOS, __FILE__, __LINE__ + 1
    def test_eval_string
    end
  EOS

  # class_eval (ブロック)
  class_eval do
    def test_eval_block
    end
  end
end

n = 10000000
test = Test.new

Benchmark.bm do |b|
  b.report '通常のメソッド' do
    n.times { test.test_normal }
  end

  b.report 'define_method' do
    n.times { test.test_define_method }
  end

  b.report 'class_eval (文字列)' do
    n.times { test.test_eval_string }
  end

  b.report 'class_eval (ブロック)' do
    n.times { test.test_eval_block }
  end
end

結果

define_method版が他に比べて2倍近く時間がかかる一方、他の方法はほとんど時間が変わらないことがわかりました。

ベンチマーク結果
       user     system      total        real
通常のメソッド  0.880000   0.000000   0.880000 (  0.880378)
define_method  1.520000   0.000000   1.520000 (  1.527402)
class_eval (文字列)  0.890000   0.000000   0.890000 (  0.893508)
class_eval (ブロック)  0.880000   0.000000   0.880000 (  0.884782)

まとめ

やはりdefine_methodで定義したメソッドは遅い

define_method版は他に比べて2倍近く遅いという結果になりました。

今回は何も行わないメソッドでのベンチマークだったので結果が極端になりましたが、
通常のプログラミングでも、メソッド呼出のコストを考慮しなければいけない場合 (メソッドの内容が少ないなど) は、define_methodの遅さを気にする必要がありそうです。

文字列class_evalで定義したメソッドは通常のメソッドと呼出コストが変わらない

一方、文字列class_evalを使えば、通常のメソッドと同じ速さのメソッドを動的に定義できる (文字列しか動的に操作できないというデメリットがありますが) ということもわかりました。

42
39
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?