外部のリソースを複数openするようなとき,1つずつ順番にやっていると,時間がかかってしまう.
require 'open-uri' urls = %w{ a b d f g graph}.map{ |service| "http://#{service}.hatena.ne.jp/hitode909/" } contents = urls.map{ |url| open(url).read }
これは17秒かかる.
並列に実行して,それらが終わるのを待つようにすると,実行時間を短縮できる.
いいライブラリを使えばいい感じにできそうだけど,1つずつThreadを作って,あとで順番にjoinすると,簡単にできる.
require 'open-uri' urls = %w{ a b d f g graph}.map{ |service| "http://#{service}.hatena.ne.jp/hitode909/" } contents = [] threads = urls.map{ |url| Thread.new{ contents << open(url).read } } threads.each{ |thread| thread.join }
これなら7秒で終わる.
1つだけ重いサーバーがあったりするとなかなか終わらなくて困ったりする.
こうすると,最悪3秒待って,終わってなくても次の処理に進める.
タイムアウトして処理が打ち切られるわけではなくて,あとで,contentsがだんだん増えていったりするので,気をつけないとおかしくなる.
require 'open-uri' require 'timeout' urls = %w{ a b d f g graph}.map{ |service| "http://#{service}.hatena.ne.jp/hitode909/" } contents = [] threads = urls.map{ |url| Thread.new{ contents << open(url).read } } begin timeout(3) { threads.each{ |thread| thread.join } } rescue Timeout::Error end
取得できないのもあるけど,とりあえず3秒で終わる.なんでもいいから3秒分ほしいときとか.
逆に,urlsがめちゃくちゃ多いときは,一度に大量のリクエストが飛んでしまって,DoS攻撃みたいになってしまうので,気をつける必要がある.そういう場合は1個ずつ取得するほうがよさそう.