Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
70
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

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

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 も簡単で試してみる価値ありそうです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
70
Help us understand the problem. What are the problem?