2009年4月8日水曜日

How Fast is JRuby

How JRuby Makes Ruby Fast

def tak x, y, z
if y >= x
return z
else
return tak( tak(x-1, y, z),
tak(y-1, z, x),
tak(z-1, x, y))
end
end

tak(24, 16, 8)を10回分の時間はいかほど?

user system total real
0.524000 0.000000 0.524000 ( 0.524000)
0.338000 0.000000 0.338000 ( 0.338000)
0.325000 0.000000 0.325000 ( 0.325000)
0.299000 0.000000 0.299000 ( 0.299000)
0.310000 0.000000 0.310000 ( 0.310000)

JRubyはええええええ。
と思ったけど、Rubyの速さをよく知らないので、わからない。
あまりベンチマークに興味を持ったことがない。

一応、手元のJRubyでも試したよ。
jruby --server --fast tak.rb

user system total real
1.281000 0.000000 1.281000 ( 1.219000)
0.906000 0.000000 0.906000 ( 0.906000)
0.906000 0.000000 0.906000 ( 0.906000)
0.922000 0.000000 0.922000 ( 0.922000)


とりあえずPythonと比較してみた。
ここはさくっと1秒をきってもらいたいところ。

def tak(x, y, z):
if y >= x:
return z
else:
return tak(tak(x-1, y, z),
tak(y-1, z, x),
tak(z-1, x, y))

python tak.py

4.68799996376s
4.67199993134s
4.71900010109s
4.70300006866s

。。。

気を取り直して、Jython。
まあ、期待してないっす。Pythonの倍ぐらい遅くてもぜんぜん気にしないっす。
だって、お金かかってないっすからね。
Pythonと同じソースが走るのは優秀っすね。
jython tak.py

12.2509999275s
12.1879999638s
12.2030000687s
12.1879999638s

。。。


Ironのじつりきに期待したいけど、ビルドしたことなかった。
いつか誰かがやります。


ところでさ、Javaだとどんなもんかな。
0.3秒が数倍遅いって言ってるんだから、0.08秒ぐらいか。
そりゃはやいね。

static int tak(int x, int y, int z) {
if (y >= x)
return z;
else
return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y));
}

java Tak.java

0.107289151s
0.107325477s
0.107177706s
0.10697179s

JRubyはえええええ!
しかし、ここはJavaのすごいところが見たい!
java -server Tak.java

0.094475588s
0.081646268s
0.081483518s
0.08147525s

やっぱりJRubyはええええ。
ええい、他にオプションはないのか。

というわけでJRubyの速さを際立たせるだけでした。
あ、そうだ。
Dubyが早いならGroovyも型を指定すれば早いんじゃね?
cp Tak.java Tak.groovy
groovy Tak.groovy

6.369433797s
6.266855432s
6.264844057s
6.277156358s

本気か?
事前にコンパイルしないとだめか、そうかそうか。

groovyc Tak.groovy
groovy Tak

6.336249071s
6.235964946s
6.235621352s
6.233301473s

ち、ちょっと早くなったのかしら。

型を指定してあげてるのにこんなに遅いって、Groovyは駄目な子なのか。
ちなみに型を指定しなかったらJythonより遅いのか。
SpringSourceしっかりしろよ。
怖いもの見たさでチェック

def tak(x, y, z) {
if (y >= x)
return z;
else
return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y));
}


3.599673454s
3.504575443s
3.504178545s
3.503208614s

おおおおおお!どうなってるんですか?
速くなりました。
倍近く早いよ。
ってか、Pythonより速い。
Groovyやるな!
ってか、なんで?

ここまできたらScalaも試そうか。

def tak(x: Int, y: Int, z: Int): Int = {
if (y >= x) z else tak( tak(x-1, y, z),
tak(y-1, z, x),
tak(z-1, x, y))
}

scala Tak_scala

0.191174899s
0.185557729s
0.18544463s
0.185426475s

思ったより少しだけ遅いけど、悪くないね。
serverモードはないのかな?


というわけでGroovyの変態さが伝わったかな?
本当はIokeでも試したんだけど、まったく答えが返ってこないのでなかったことにしました。

このまま終わると晩御飯をおいしく食べられないので、Pythonでもうチョイがんばります。
まずはご存知psyco

import psyco
psyco.full()

と先頭につけるだけ。

0.281000137329s
0.296999931335s
0.296999931335s
0.281000137329s

おお、いいね。JRubyに勝った!

つづいてCython

cdef int ctak(int x, int y, int z):
if y >= x:
return z
else:
return ctak(ctak(x-1, y, z),
ctak(y-1, z, x),
ctak(z-1, x, y))


0.155999898911s
0.171999931335s
0.156000137329s
0.155999898911s

よし、Scalaに勝った!


やっぱりPythonだね。

ごらんのスポンサーの提供でお送りしました。
java version "1.6.0_11"
Scala code runner version 2.7.3.final
jruby 1.3.0 (ruby 1.8.6p287) (2009-04-08 r)
Jython 2.5b1 (trunk:5903:5905, Jan 9 2009, 16:01:29)
Python 2.6.1
Groovy Version: 1.6.1

TODO
グラフを貼る


結論。
Groovyは型を指定すると遅くなる。