SinatraをCGIで動かして、他のフレームワークと起動性能を比較してみた
実行速度的にも軽いのかな。以前、下記のエントリでやったように、CGI+rubyで性能比較してみようかな。
Sinatra良いかも - NAT’s Programming Champloo
こんな事を書いておきながら、長い間ほったらかしなので、SinatraをCGI起動で試してみた。
sinataをCGIで起動するコード
CGIから起動する方法は、以下を参考にさせて頂きました。
http://blog.shockby.com/2009/04/22/sinatra%E3%80%81%E7%B5%90%E6%A7%8B%E3%81%84%E3%81%84%E3%81%8B%E3%82%82/
http://dgames.jp/dan/permalink/20090508_01
単に "Hello, World" と表示するコードは、以下のようになる。
#!/usr/bin/ruby require 'rubygems' require 'sinatra' require 'rack' get '' do 'Hello, World' end set :run => false, :environment => :production Rack::Handler::CGI.run Sinatra::Application
「get '/'」でなく「get ''」とするのが注意点。Sinatraはエラー時の表示も親切で、こういう誤りにもすぐ気づけるのが良い。ブラウザに以下のように出力される。
Sinatra doesn't know this ditty. Try this: get '' do "Hello World" end
CGI起動性能比較
私が利用しているさくらのレンタルサーバは、常時起動しているプロセスが作れないので、CGI起動でしかrubyアプリを公開できない。そのため、起動性能が早い方が嬉しい。というわけで、以前のエントリでやったように、CGI起動性能を他のフレームワークと比較することにした。
rubyの軽いWebアプリケーションフレームワークを試してみた - NAT’s Programming Champloo
今回の比較対象は、下記のフレームワーク。
- CGI: rubyの添付ライブラリ
- Rack: 正確には、Webサーバとフレームワークを接続するミドルウェアで、Sinatraもこれベースだけど、比較対象として
- Ramaze: 利用できるテンプレートやORM等の自由度が高い軽量フレームワーク
- Sinatra: 今回の性能比較のターゲット
性能比較は前回と同様、「Hello, World」と表示するWebアプリに対してHTTPリクエストを100回投げて、その所要時間を比較するという単純なもの。アプリおよび計測用コードは、このエントリの最後に記載します。
手元のMacBook Pro(CPU:Intel Core 2 Duo 2.2Ghz, メモリ:2GB, OS:Mac OS X 10.5.4)で所要時間を計測したところ、下記のような結果になった。
user system total real cgi 0.100000 0.030000 0.130000 ( 1.849285) rack 0.120000 0.050000 0.170000 ( 14.419194) ramaze 0.130000 0.070000 0.200000 ( 28.720612) sinatra 0.130000 0.060000 0.190000 ( 18.329908)
real時間で見ると、sinatraがrackに対して27%大きく、ramazeに対して36%小さいという結果になった。
思ったよりramazeとの差が大きいという印象。コードもシンプルに書けるし、ソースファイル1つで書くようなちょっとしたWebアプリなら、sinatraが良さそうですね。
とはいえ、機能面やドキュメント整備の面ではramazeの方が進んでいる印象なので、View(テンプレート)とController(rubyコード)を分けたくなるような、そこそこ複雑なWebアプリならramazeという選択肢もありますね。
ちなみに、CGI環境でないなら、CGI起動性能はほとんど意味がなくなるので、純粋にコードの書き方の好みや機能面などで選ぶことになるでしょう。
CGI起動性能比較に使ったコード
CGI
#!/usr/bin/ruby require 'cgi' cgi = CGI.new cgi.out() do "Hello, World." end
rack
#!/usr/bin/ruby require 'rubygems' require 'rack' class HelloWorld def call(env) [200, {'Content-Type'=>'text/html'}, ["Hello, World."]] end end Rack::Handler::CGI.run HelloWorld.new
ramaze
#!/usr/bin/ruby require 'rubygems' require 'ramaze' class MainController < Ramaze::Controller map '/' def index "Hello, World" end end Ramaze.start :adapter => :cgi
起動性能計測用コード
require 'benchmark' require 'open-uri' count = 100 count = ARGV[0].to_i if ARGV[0] class Loader def initialize(n = 1, prefix = '') @prefix = prefix @n = n end def load(path) contents = '' @n.times do open(@prefix + path) do |f| contents = f.read end end # puts contents end end loader = Loader.new(count, "http://localhost/~NAT/cgi/") Benchmark.bmbm do |r| r.report("cgi") { loader.load("hello_cgi.cgi") } r.report("rack") { loader.load("hello_rack.cgi") } r.report("ramaze") { loader.load("hello_ramaze.cgi") } r.report("sinatra") { loader.load("hello_sinatra.cgi") } end