SinatraをCGIで動かして、他のフレームワークと起動性能を比較してみた

実行速度的にも軽いのかな。以前、下記のエントリでやったように、CGI+rubyで性能比較してみようかな。

Sinatra良いかも - NAT’s Programming Champloo

こんな事を書いておきながら、長い間ほったらかしなので、SinatraCGI起動で試してみた。

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


今回の比較対象は、下記のフレームワーク

性能比較は前回と同様、「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
sinatra

このエントリの最初を参照

起動性能計測用コード
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