mswin32 ならどうか。 (先日のものより、試行回数を 5 倍に増やしています)
user system total real
0.655000 0.000000 0.655000 ( 0.661834)
0.671000 0.000000 0.671000 ( 0.669683)
0.780000 0.000000 0.780000 ( 0.775580)
2.901000 0.000000 2.901000 ( 2.899961)
9.111000 0.000000 9.111000 ( 9.118487)
10.311000 0.000000 10.311000 ( 10.313085)
11.420000 0.000000 11.420000 ( 11.439372)
13.977000 0.000000 13.977000 ( 14.013315)
21.763000 0.000000 21.763000 ( 21.772048)
15.350000 0.000000 15.350000 ( 15.402681)
これが、
user system total real
0.624000 0.000000 0.624000 ( 0.620226)
0.655000 0.000000 0.655000 ( 0.656366)
0.796000 0.000000 0.796000 ( 0.788591)
0.874000 0.000000 0.874000 ( 0.882641)
1.014000 0.000000 1.014000 ( 1.015402)
1.029000 0.000000 1.029000 ( 1.047946)
1.092000 0.000000 1.092000 ( 1.086839)
1.201000 0.000000 1.201000 ( 1.203149)
1.248000 0.000000 1.248000 ( 1.237409)
1.264000 0.000000 1.264000 ( 1.264578)
圧倒的だった。
user system total real
0.060000 0.000000 0.060000 ( 0.065711)
0.080000 0.000000 0.080000 ( 0.071005)
0.070000 0.000000 0.070000 ( 0.071445)
0.100000 0.000000 0.100000 ( 0.097273)
0.110000 0.000000 0.110000 ( 0.113550)
0.120000 0.000000 0.120000 ( 0.120162)
0.120000 0.000000 0.120000 ( 0.124773)
0.120000 0.000000 0.120000 ( 0.123037)
0.130000 0.000000 0.130000 ( 0.124647)
0.120000 0.000000 0.120000 ( 0.124635)
大分頑張った!
参考:2.2.0 trunk
user system total real
0.070000 0.000000 0.070000 ( 0.064943)
0.060000 0.000000 0.060000 ( 0.066670)
0.070000 0.000000 0.070000 ( 0.072237)
0.250000 0.000000 0.250000 ( 0.253850)
1.020000 0.000000 1.020000 ( 1.022563)
1.170000 0.000000 1.170000 ( 1.163268)
1.290000 0.010000 1.300000 ( 1.297507)
1.450000 0.000000 1.450000 ( 1.450783)
1.590000 0.000000 1.590000 ( 1.586544)
1.710000 0.000000 1.710000 ( 1.715250)
これは10倍速くなったと言っていいんじゃないか。
まぁ、だいぶインチキが混じっているのですが。でも、ソコソコ効くんじゃ無いだろうか。どんなインチキかというと、キーワードパラメータが nil の時とかに速くなる、という。あとは、どんなのが指定されることが多いんだろうな。文字列くらいサポートしてあげたいような。
先日の記事で、キーワード引数を使うと遅い、という話を書きました(http://www.atdot.net/~ko1/diary/201410.html#d11)。
ちょっと環境が変わったので、改めて測ります。
# ruby 2.2.0dev (2014-10-14 trunk 47859) [x86_64-linux]
user system total real
0.070000 0.000000 0.070000 ( 0.065488)
0.060000 0.000000 0.060000 ( 0.065363)
0.070000 0.000000 0.070000 ( 0.072903)
0.270000 0.000000 0.270000 ( 0.266412)
1.040000 0.000000 1.040000 ( 1.038621)
1.200000 0.000000 1.200000 ( 1.201818)
1.370000 0.000000 1.370000 ( 1.376191)
1.430000 0.000000 1.430000 ( 1.423747)
1.540000 0.000000 1.540000 ( 1.549852)
1.730000 0.000000 1.730000 ( 1.724549)
最初(無引数)と最後(kwarg を 6 個渡す)を比べると、1.73 / 0.07 = 24 倍遅い。
で、これをなんとか速くならんかな、と思って色々やった結果がこれです。
user system total real
0.070000 0.000000 0.070000 ( 0.071088)
0.060000 0.000000 0.060000 ( 0.066202)
0.080000 0.000000 0.080000 ( 0.074154)
0.230000 0.000000 0.230000 ( 0.233521)
0.300000 0.000000 0.300000 ( 0.299151)
0.350000 0.000000 0.350000 ( 0.353437)
0.410000 0.000000 0.410000 ( 0.409449)
0.460000 0.000000 0.460000 ( 0.455629)
0.490000 0.000000 0.490000 ( 0.494256)
0.530000 0.000000 0.530000 ( 0.535178)
最初と最後を比べると、0.53 / 0.07 = 7.57 倍遅い。
遅さが 24 / 7.57 = 3 倍、改善しました。
うーん、もっと速くなると思ったんだけどな。
というわけで、Ruby 2.2 は、キーワード引数によるメソッド呼び出しが速くなるかもしれません。
その代わり、他の箇所が遅くなっている可能性が...。
しかし、どこが遅いんだろうなぁ。実は、4番目(foo_kw6 に無引数で渡す)が、もっと速くなると踏んでいたんだけどな。Hash#key? の呼び出しって速いのか?
ちょっとだけ弄ってみた。
user system total real
0.070000 0.000000 0.070000 ( 0.067622)
0.070000 0.000000 0.070000 ( 0.069523)
0.070000 0.000000 0.070000 ( 0.073671)
0.230000 0.000000 0.230000 ( 0.231982)
0.310000 0.000000 0.310000 ( 0.302289)
0.350000 0.000000 0.350000 ( 0.352416)
0.420000 0.000000 0.420000 ( 0.423110)
0.470000 0.000000 0.470000 ( 0.469080)
0.500000 0.000000 0.500000 ( 0.499148)
0.550000 0.000000 0.550000 ( 0.550228)
むしろ遅くなってる! うーん。
もうちょっと頑張ったが、
user system total real
0.070000 0.000000 0.070000 ( 0.066390)
0.060000 0.000000 0.060000 ( 0.069617)
0.080000 0.000000 0.080000 ( 0.075847)
0.260000 0.000000 0.260000 ( 0.258485)
0.310000 0.000000 0.310000 ( 0.313561)
0.360000 0.000000 0.360000 ( 0.357482)
0.410000 0.000000 0.410000 ( 0.415190)
0.460000 0.000000 0.460000 ( 0.460494)
0.480000 0.000000 0.480000 ( 0.485287)
0.560000 0.000000 0.560000 ( 0.559535)
あんまり変わんないな。うーん。
いつの間にか 10 月ですよ...。
Ruby 2.0 から導入されたキーワード引数の性能評価。
require 'benchmark'
def foo0
end
def foo3 a, b, c
end
def foo6 a, b, c, d, e, f
end
def foo_kw6 k1: nil, k2: nil, k3: nil, k4: nil, k5: nil, k6: nil
end
N = 1_000_000
Benchmark.bm{|x|
x.report{
N.times{
foo0
}
}
x.report{
N.times{
foo3 1, 2, 3
}
}
x.report{
N.times{
foo6 1, 2, 3, 4, 5, 6
}
}
x.report{
N.times{
foo_kw6
}
}
x.report{
N.times{
foo_kw6 k1: 1
}
}
x.report{
N.times{
foo_kw6 k1: 1, k2: 2
}
}
x.report{
N.times{
foo_kw6 k1: 1, k2: 2, k3: 3
}
}
x.report{
N.times{
foo_kw6 k1: 1, k2: 2, k3: 3, k4: 4
}
}
x.report{
N.times{
foo_kw6 k1: 1, k2: 2, k3: 3, k4: 4, k5: 5
}
}
x.report{
N.times{
foo_kw6 k1: 1, k2: 2, k3: 3, k4: 4, k5: 5, k6: 6
}
}
}
何をしているかというと、
と、いうのが、どんな性能特性を持つか調べたいと思います。
というか、結果。
ruby 2.2.0dev (2014-10-10 trunk 47867) [i386-mswin32_110]
user system total real
0.140000 0.000000 0.140000 ( 0.134481)
0.141000 0.000000 0.141000 ( 0.140427)
0.171000 0.000000 0.171000 ( 0.180837)
0.593000 0.000000 0.593000 ( 0.595162)
1.778000 0.016000 1.794000 ( 1.787873)
2.028000 0.000000 2.028000 ( 2.034146)
2.247000 0.000000 2.247000 ( 2.255171)
2.464000 0.000000 2.464000 ( 2.470283)
2.621000 0.000000 2.621000 ( 2.639155)
2.855000 0.000000 2.855000 ( 2.863643)
キーワード引数のほうは、キーワードの数に大分比例している感じですね。これは、多分、呼び出し側で Hash 作ってるんだけど、その生成コストなんじゃないかな、って思う。
6引数のメソッドで渡す場合(0.17 秒)に比べて、6個キーワード引数渡すと、2.85 秒と、10倍以上遅いことがわかります。
続きます。
おまけ
def foo a, b, k1: eval('kr.dup'), k2: 2, **kr
p k1
end
foo 1, 2, k2: 'v2', k3: 'v3'
何が表示されるか。
最後の **kr では、keyword 引数で指定しなかった {k3: 'v3'} というものが得られるはずだが、実装の都合で k1 のデフォルト引数を評価中は、まだ k2 が残ってしまうので、{:k2=>"v2", :k3=>"v3"} が見えてしまう、という。dup しないと、その時の snapshot が見えない。