@m_seki の

I like ruby tooから引っ越し

遠慮がちなQueue

ずいぶん前にクロウラみたいなの書こうと思って飽きちゃったネタ。なるべく同じホストへのリクエストが連続しないようにするへんなQueue。

require 'monitor'
require 'thread'
require 'uri'

class ReservedQueue
  include MonitorMixin
  def initialize
    super()
    @queue = Queue.new
    @bin = Hash.new {|h, k| h[k] = []; @queue.push(h[k]); h[k]}
  end
  
  def push(uri)
    synchronize do
      ary = @bin[key(uri)]
      ary.push(uri)
    end
  end

  def pop
    synchronize do
      begin
        ary = @queue.pop
      end while ary.empty?
      uri = ary.shift
      if ary.empty?
        @bin.delete(key(uri))
      else
        @queue.push(ary)
      end
      return uri
    end
  end

  def key(uri)
    uri.host
  end
end

同じホストへのリクエストは末尾へ並べ直す。

  rq = ReservedQueue.new
  rq.push(URI.parse('http://www.google.com/1'))
  rq.push(URI.parse('http://www.druby.org/1'))
  rq.push(URI.parse('http://www.druby.org/2'))
  rq.push(URI.parse('http://www.druby.org/3'))
  rq.push(URI.parse('http://www.druby.org/4'))
  rq.push(URI.parse('http://www.google.com/2'))
  rq.push(URI.parse('http://www.amaazon.co.jp'))
  rq.push(URI.parse('http://www.druby.org/5'))
  rq.push(URI.parse('http://www.google.com/2'))
  begin
    while true
      puts rq.pop
    end
  rescue ThreadError
  end

コネクションを使い回すとかの理由でおなじホストへのリクエストを連続して取得したいなら、単にArrayの方を返せばよいんだろな。

  def pop
    @queue.pop
  end