せっかく、PerlからC言語の関数を呼び出す方法が分かったので、同じようなことをRubyでもやってみました。参考にしたのは、以下のサイトです。
http://ruby.gfd-dennou.org/tutorial/ruby-ext/
- prime.cを作成
long isprime(long lObj) { long j; for (j = 2; j*j <= lObj; ++j) { if (lObj % j == 0) return 0; } return 1; } long prime(long lLmtCnt) { long lCnt = 0, lObj; for (lObj = 2; lCnt < lLmtCnt; ++lObj) { lCnt += isprime(lObj); } return lObj - 1; }
- Swigに対する入力ファイルとしてprime.iを作成
%module Prime %{ %} extern int prime(long lLmtCnt);
- Swigで処理してラッパー関数を作成
$ swig -ruby prime.i
- extconf.rbの作成
require 'mkmf' create_makefile('Prime')
mmasa@debian:~/work/ruby/ext/Prime/swig$ ruby extconf.rb creating Makefile mmasa@debian:~/work/ruby/ext/Prime/swig$ make
- 動作テスト(Prime_ext.rb)
#!/usr/bin/ruby require 'Prime' print Prime.prime(ARGV[0].to_i), "\n"
mmasa@debian:~/work/ruby/ext/Prime/swig$ ruby Prime_ext.rb 100 541
Prime.rbとPrime_ext.rbの比較
Prime.rbは以下です。
#!/usr/bin/ruby def isprime(lObj) j = 2 while j*j <= lObj return 0 if (lObj % j) == 0 j+=1 end return 1 end def prime(lLmtCnt) lCnt = 0 lObj = 2 while lCnt < lLmtCnt lCnt += isprime(lObj) lObj += 1 end return lObj - 1 end print prime(ARGV[0].to_i), "\n"
Bench.plは以下です。
#!/usr/bin/perl -w use strict; use Benchmark; timethese(200, { 'Ruby :' => "system('ruby Prime.rb 2000 > /dev/null')", 'Ruby-ext:' => "system('(cd swig;ruby Prime_ext.rb 2000 > /dev/null)')", });
実行結果は以下のようになりました。Prime.rbの書き方がまずいということもあると思いますが、両者には相当な性能差があることが分かりました。
mmasa@debian:~/work/ruby/ext/Prime$ perl Bench.pl Benchmark: timing 200 iterations of Ruby :, Ruby-ext:... Ruby :: 59 wallclock secs ( 0.00 usr 0.05 sys + 49.19 cusr 6.62 csys = 55.86 CPU) @ 4000.00/s (n=200) Ruby-ext:: 2 wallclock secs ( 0.00 usr 0.05 sys + 0.18 cusr 2.29 csys = 2.52 CPU) @ 4000.00/s (n=200)