LoginSignup
87
72

More than 5 years have passed since last update.

Ruby の HTTP リクエストを送る方法の性能比較

Last updated at Posted at 2015-07-22

HTTP リクエストの性能比較をさまざまな Gem などで行ってみた。

net-http

一番標準的な Net::HTTP を使ってみる。

net-http.rb
require "net/http"

100.times do
  res = Net::HTTP.start("www.yahoo.co.jp") do |http|
    http.get "/"
  end
  res.body
end

open-uri

みんな大好き open-uri も試してみる。

open-uri.rb
require "open-uri"

100.times do
   body = open("http://yahoo.co.jp", &:read)
end

persistent_http

persistent_http を使ってみた。

persistent-http.rb
require "persistent_http"

http = PersistentHTTP.new(
  :name => "MyHTTPClient",
  :pool_size => 3,
  :pool_timeout => 5,
  :warn_timeout => 0.25,
  :force_retry => true,
  :url => "http://www.yahoo.co.jp/"
)

100.times do
  response = http.request
  response.body
end

Net::HTTP (オブジェクト再利用)

標準ライブラリの Net::HTTP でオブジェクトを再利用したバージョン。

persistent-net-http.rb
require "net/http"

Net::HTTP.start("www.yahoo.co.jp") do |http|
  100.times do
    res = http.get "/"
    res.body
  end
end

wget

意表を突いて、 Open3 + wget も試してみるテスト。

wget.rb
require "open3"

100.times do
  stdout, stderr, exitcode = Open3.capture3("wget -d -O - http://www.yahoo.co.jp")
end

excon

excon を使ってみた。
リポジトリ中に Benchmark の実装もあるが、気にせず、独自に検証。

excon.rb

require "excon"

connection = Excon.new("http://www.yahoo.co.jp", persistent: true)

100.times do
  get_response = connection.get(path: "/")
  get_response.body
end

curb

libcurl を使った実装の1つ curb を使ってみた。
今回の実装では凝ったことをしてみた。

curb.rb
require "curb"

curl = Curl::Easy.new

urls = ["http://www.yahoo.co.jp/"] * 100

multi = Curl::Multi.new

responses = Hash.new do |hash, k|
  hash[k] = ""
end

urls.each do |url|
  curl = Curl::Easy.new url do |easy|
    easy.on_body do |data|
      responses[url] << data; data.size
    end
  end
  multi.add curl
end

multi.perform do
end

urls.each do |url|
  responses[url]
end

em-synchrony

EventMachine を使った実装の1つ em-synchrony を使ってみた。

em-synchrony.rb
require "em-synchrony"
require "em-synchrony/em-http"
require "em-synchrony/fiber_iterator"

urls = [ "http://www.yahoo.co.jp/" ] * 100

responses = Enumerator.new do |y|
  EM.synchrony do
    concurrency = 1

    EM::Synchrony::FiberIterator.new( urls, concurrency ).each do |url|
      y << [ url, EventMachine::HttpRequest.new(url).get ]
    end
    EventMachine.stop
  end
end

responses.each do |url, response|
end

typhoeus

libcurl を使った実装の1つtyphoeus を使ってみた。

typhoeus
require "typhoeus"

100.times do
  Typhoeus.get("www.yahoo.co.jp/")
end

httparty

なんとなく楽しそうな印象の HTTParty も使ってみた。

httparty.rb
require "httparty"

100.times do
  response = HTTParty.get('http://www.yahoo.co.jp/')
end

計測結果

実行時間は time コマンドで測定。

ファイル名 実行時間
net-htp.rb 11.712s
open-uri.rb 22.079s
persistent-http.rb 17.293s
persistent-net-htp.rb 16.401s
wget.rb 14.450s
excon.rb 25.299s
curb.rb 20.234s
em-synchrony.rb 8.906s
typhoeus.rb 8.909s
httparty.rb 12.472s

Faraday 系の Gem は内部の Gem を直接使う場合に
比べて遅そうなので、試していません。

考察

たとえ concurrency が 1 でも、EventMachine を使う em-synchrony が最速という結果は少し意外でした。

実行タイミングによる差も非常に大きく、時間帯によっては上記の 2倍くらいの時間となることもあるので、上記の結果の信頼性はかなり低いです。
また www.yahoo.co.jp ではなく、もっと違う WEB サーバで試すべきかもしれません。
ただし、やっていることはほとんどアタックなので、自重しましょう。

私の中では

  • 安定した実行性能(実行時間の標準偏差が小さいこと)
  • 手馴れていること
  • 異常時のデバッグログ取得などもやりやすいこと
  • コード量も短くなること

などから wget を Open3 で実行した結果を使うことにしました。

ちゃんちゃん。

追記

コメントをいただいたので、追加で typhoeus を試してみました。さらについでに HTTParty も試してみました。

typhoeus は速いですね。
機能も豊富そうな上に API も簡単で試してみる価値ありそうです。

87
72
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
87
72