この記事ではRuby2.2.3とGo1.5.1を使用しています。
すごい要約
Go and Ruby-FFI - Code7 Interactiveを読むといい。
Go、はやい
最初にRubyとGoの計算速度を比べるため、フィボナッチ数を単純に計算するやつをそれぞれ書きました。
def fib(n)
return n if n <= 1
fib(n - 1) + fib(n - 2)
end
puts fib(40)
package main
import "fmt"
func fib(n uint) uint {
if n <= 1 {
return n
}
return fib(n-1) + fib(n-2)
}
func main() {
fmt.Println(fib(40))
}
比較のためにできるだけ単純に同じロジックで実装しました。
実行結果は以下です。
> time ruby fib.rb
102334155
ruby fib.rb 19.00s user 0.11s system 92% cpu 20.690 total
> time go run fib.go
102334155
go run fib.go 1.24s user 0.25s system 84% cpu 1.758 total
> time ./fib
102334155
./fib 0.80s user 0.01s system 89% cpu 0.903 total
この処理だと圧倒的にGoの方がはやいようです。
「Rubyより、ずっとはやい!!!!!!」
Goを共有ライブラリにする
GoをRubyから利用するためには、まずShared Libraryとしてコンパイルします。
ここらへんは「Golang で Shared Library を出力する。」を参考にさせていただきました。
Goのビルド時に-buildmode=c-shared
オプションを渡すとよしなにしてくれます。
ただ、今のままだとRubyから関数が呼べないのでGoのソースを書き換えます。
package main
import "C"
//export fib
func fib(n uint) uint {
if n <= 1 {
return n
}
return fib(n-1) + fib(n-2)
}
func main() {}
ポイントはCをインポートするのと、//export fib
を追記する点です。
Rubyから呼べる関数を明示的に選べます。
main()
は実行されませんが、コンパイル上必要なので書いておきます。
これで
> go build -buildmode=c-shared -o fib.so fib.go
fib.so と fib.h がディレクトリに作成されたら成功です。
RubyからGoの関数を呼ぶ
共有ライブラリとしてコンパイルしたGoをRubyから扱うにはFFIを使用します。
そもそもFFIとはForeign function interfaceの略で、ffiというgemがこれをRubyでもいい感じにやるぞ!ってやつです。
まずインストール。
> gem install ffi
Ruby-FFIはRubyのオブジェクトに他言語の関数をアタッチしていく感覚で使用します。
require "ffi"
module Fib
extend FFI::Library
ffi_lib "fib.so"
attach_function :fib, [:uint], :uint
end
puts Fib.fib(40)
このattach_function()
の引数は、「関数名、[関数の引数型]、戻り値型」です。
ちなみに型として利用できるのはTypes · ffi/ffi Wikiに一覧があります。
今回は数値だったのでそこまで問題はありませんが、文字列をやりとりする場合は、
Goの関数内で受け取ったCのstringをC.GoString(str)
としたり、逆にGoのstringをC.CString("Go no string dayo!!!!!")
するなど適宜変換してあげる必要があります。
詳しくはcgo - The Go Programming Languageを参照!!!
Ruby meets Go
はいここまで長かった!
速度の計測です。
> time ruby fib.rb
102334155
ruby fib.rb 19.00s user 0.11s system 92% cpu 20.690 total
> time ruby go-fib.rb
102334155
ruby go-fib.rb 0.85s user 0.06s system 95% cpu 0.953 total
約20倍はやい!!!!!!すごい!!!!!!!!!!!!!!
Go単体での実行に毛が生えた程度になりました!!!!!!!!!!!!!!!!!!
もう「Rubyより、ずっとはやい」なんて言わせないぞ!!!!!!!!
こうやってそれぞれの得意分野でよろしくやっていくのが平和でよいなと思いました。
参考
Golang で Shared Library を出力する。 - Qiita
ffi/ffi
cgo - The Go Programming Language
Go and Ruby-FFI - Code7 Interactive