curb(Rubyのcurlバインディング)で並列リクエストを試す
gemでインストールしたcurb(Rubyのcurlバインディング)のrdocを見ていたらCurl::Multiっていうクラスがあって、並列でURLリクエストできそうだったので試してみた。
※2010/06/15現在、WEB上に置いてあるcurbのオンラインドキュメントは結構古いようで(CURB_VERSION定数をみると"0.1.4"って書いてある)この頃はまだCurl::Multiが未実装っぽい。
直近でインストールしたcurbのライブラリバージョンは0.7.6
$ gem list curb -d *** LOCAL GEMS *** curb (0.7.6, 0.7.5) Authors: Ross Bamford, Todd A. Fisher Rubyforge: http://rubyforge.org/projects/curb Homepage: http://curb.rubyforge.org/ Installed at (0.7.6): /usr/local/lib/ruby/gems/1.8 (0.7.5): /usr/local/lib/ruby/gems/1.8 Ruby libcurl bindings
以下、テストスクリプト。
test_curb.rb
#!/usr/bin/env ruby # -*- coding:utf8 -*- require 'rubygems' require 'curb' MyResponse = Struct.new(:url, :code, :body, :time) responses = [] requests = [ 'http://dailynews.yahoo.co.jp/fc/rss.xml', 'http://feeds.builder.japan.zdnet.com/builder/rss', 'http://feeds.feedburner.com/hatena/b/hotentry', 'http://japan.internet.com/rss/rdf/topics.rdf', 'http://rss.rssad.jp/rss/wiredvision/feed/atom.xml', 'http://rss.rssad.jp/hogehoge/hogehoge.xml', # 存在しないコンテンツのURL 'http://hogehoge.example.com/hogehoge.xml' # 存在しないホストのURL ] puts "Start" time_begin = Time.now m = Curl::Multi.new m.pipeline = true requests.each do |url| m.add( Curl::Easy.new(url) do |curl| curl.follow_location = true curl.on_complete do |ch| responses << MyResponse.new(url, ch.response_code, ch.body_str, ch.total_time) end end ) end m.perform do puts "idling... can do some work here, including add new requests" end responses.each do |res| puts res.url puts " code = #{res.code}" puts " body.size = #{res.body.size}" puts " time = #{res.time}" puts '---' end puts "End time:#{Time.now - time_begin}" puts
実行結果
$ ruby -v ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-linux] $ ruby test_curb.rb Start http://hogehoge.example.com/hogehoge.xml code = 0 body.size = 0 time = 0.0 --- http://rss.rssad.jp/hogehoge/hogehoge.xml code = 404 body.size = 1509 time = 0.020261 --- http://japan.internet.com/rss/rdf/topics.rdf code = 200 body.size = 5714 time = 0.026651 --- http://rss.rssad.jp/rss/wiredvision/feed/atom.xml code = 200 body.size = 107973 time = 0.044281 --- http://dailynews.yahoo.co.jp/fc/rss.xml code = 200 body.size = 3465 time = 0.046129 --- http://feeds.builder.japan.zdnet.com/builder/rss code = 200 body.size = 44936 time = 0.07544 --- http://feeds.feedburner.com/hatena/b/hotentry code = 200 body.size = 100764 time = 0.187272 --- End time:0.188435
curbが入ってない環境で(Ruby標準添付ライブラリだけで)同じようなことをやるならNet::HTTPとThreadを使って↓こんな感じか。多分。
test_thread.rb
#!/usr/bin/env ruby # -*- coding:utf8 -*- require 'uri' require 'net/http' Net::HTTP.version_1_2 MyResponse = Struct.new(:url, :code, :body, :time) responses = [] requests = [ 'http://dailynews.yahoo.co.jp/fc/rss.xml', 'http://feeds.builder.japan.zdnet.com/builder/rss', 'http://feeds.feedburner.com/hatena/b/hotentry', 'http://japan.internet.com/rss/rdf/topics.rdf', 'http://rss.rssad.jp/rss/wiredvision/feed/atom.xml', 'http://rss.rssad.jp/hogehoge/hogehoge.xml', # 存在しないコンテンツのURL 'http://hogehoge.example.com/hogehoge.xml' # 存在しないホストのURL ] puts "Start" time_begin = Time.now threads = [] requests.each do |url| threads << Thread.new do time_b = Time.now begin res = Net::HTTP.get_response(URI.parse(url)) code = res.code body = res.body rescue StandardError => e code = 0 body = '' end responses << MyResponse.new(url, code, body, Time.now - time_b) end end threads.each do |t| t.join end responses.each do |res| puts res.url puts " code = #{res.code}" puts " body.size = #{res.body.size}" puts " time = #{res.time}" puts '---' end puts "End time:#{Time.now - time_begin}" puts
実行結果
$ ruby -v ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-linux] $ ruby test_thread.rb Start http://hogehoge.example.com/hogehoge.xml code = 0 body.size = 0 time = 0.001616 --- http://rss.rssad.jp/hogehoge/hogehoge.xml code = 404 body.size = 1509 time = 0.009805 --- http://japan.internet.com/rss/rdf/topics.rdf code = 200 body.size = 5714 time = 0.018922 --- http://dailynews.yahoo.co.jp/fc/rss.xml code = 200 body.size = 3465 time = 0.034052 --- http://rss.rssad.jp/rss/wiredvision/feed/atom.xml code = 200 body.size = 107973 time = 0.048426 --- http://feeds.builder.japan.zdnet.com/builder/rss code = 200 body.size = 44936 time = 0.102508 --- http://feeds.feedburner.com/hatena/b/hotentry code = 200 body.size = 100764 time = 0.189887 --- End time:0.196962