おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

Rubyでwebにアクセスするライブラリ、どれが速い?

なにやらRuby1.8.6のNet::HTTPは遅いという噂があります。

InfoQ: RubyのNet::HTTPで何が良くないのか?

それでは一体どのライブラリが一番速いのでしょうか。調べてみました。

大きいファイルをダウンロード

localhost(apache)に置いた10Mのファイルをダウンロードしてみました。ソースは下記の通り

require "rubygems"
require "benchmark"
require "net/http"
require "httpclient"
require "open-uri"
require "curl"

Benchmark.bm do |x|
  File.open("/tmp/openuri", "w") do |file|
    x.report("open-uri"){
      open("http://localhost/testfile") { |f|
        file.write(f.read)
      }
    }
  end
  File.open("/tmp/nethttp", "w") do |file|
    x.report("net/http"){
      Net::HTTP.start("localhost"){ |http|
        response = http.get("/testfile")
        file.write(response.body)
      }
    }
  end
  File.open("/tmp/httpclient", "w") do |file|
    x.report("httpclient"){
      c = HTTPClient.new
      html = c.get_content("http://localhost/testfile")
      file.write(html)
    }
  end
  File.open("/tmp/curl", "w") do |file|
    x.report("curl"){
      curl = Curl::Easy.perform("http://localhost/testfile")
      file.write(curl.body_str)
    }
  end
end

結果はこんな風になりました。確かにNet::HTTPは少し遅い気がします。

      user     system      total        real
open-uri  1.770000   0.930000   2.700000 (  2.958429)
net/http  1.270000   0.850000   2.120000 (  2.273792)
httpclient  0.240000   0.170000   0.410000 (  0.521244)
curl  0.020000   0.090000   0.110000 (  0.256240)

たくさんの小さなファイルをダウンロード

上記で示したURLでは「大きいファイルをダウンロードしたときにNet::HTTPが遅い」という話だったのですが、たくさんの小さなファイルにアクセスしたときはどうなのかも気になったので調べました。ソースは下記の通り。

require "rubygems"
require "benchmark"
require "net/http"
require "httpclient"
require "open-uri"
require "curl"

TIMES = 3000
Benchmark.bm do |x|
  x.report("open-uri"){
    1.upto(TIMES) do
      open("http://localhost/") { |f|
        # 何もしない
      }
    end
  }
  x.report("net/http"){
    1.upto(TIMES) do
      Net::HTTP.start("localhost"){ |http|
        response = http.get("/")
      }
    end
  }
  x.report("httpclient"){
    c = HTTPClient.new
    1.upto(TIMES) do
      html = c.get_content("http://localhost/")
    end
  }
  x.report("curl"){
    1.upto(TIMES) do
      curl = Curl::Easy.perform("http://localhost/")
    end
  }
end

結果は下記の通り。totalを見るとcurlが速そうです(realだと遅いのが気になりますが・・・)。

      user     system      total        real
open-uri  3.000000   1.210000   4.210000 (  6.274601)
net/http  1.930000   0.840000   2.770000 (  4.905418)
httpclient  2.370000   0.930000   3.300000 (  4.662102)
curl  0.650000   0.580000   1.230000 ( 11.828327)

結論

curlが使えるときはcurlを採用するのが、速さを考える上では一番良いのではないでしょうか。