速度の比較用のコードを書いた

以前書いたコードを書き直したときに、hpricotを使った方が早いかどうかしらべました。そのためにこんな感じのコードを書きました。

if RUBY_VERSION < "1.9"
  #1.8だとMethod#nameが存在しない
  class Method
    def name
      self.to_s
    end
  end
end

class Bench
  def initialize(*f)
    require 'benchmark'
    @mem = f || []
  end

  def add_method(*f)
    @mem.push(*f)
  end

  def prepare
    #1.8だとnameをto_sにしないと動かない。(Method#nameが存在しないので)
    @mem.map do  |fn|
      if fn.respond_to? :call
        [:method, fn.name, fn]
      elsif fn.first.respond_to? :call
        [:snipet, fn.first.name, fn] #fnはmethodと引数のArrayを想定
      end
    end
  end

  def message
    a = Object.constants.select{ |e| e =~ /RUBY/}
    a.each{ |e| puts "#{e} #{Object.const_get(e)}"}
    puts ""
  end

  def run(n=1)
    message
    raise("method is not found(@mem is empty)") if @mem.empty?
    Benchmark.bmbm do |x|
      prepare.each do |tag,name,m|
        case tag
        when :method
          x.report(name){ n.times{ m.call}}
        when :snipet
          x.report(name){ n.times{ m.first.call(*m[1..-1])}}
        else
         raise("not expected tag is used.")
        end
      end
    end
  end
  private :prepare
  attr_reader :mem
end


if __FILE__ == $0 #テスト用
  def f
    "test"
  end

  def g x, y
    x + y
  end

  b = Bench.new
  b.add_method(method(:f), [method(:g),1,2])
  b.run(100)
end

そして以下のようなファイルを作りhpricotに意味があるか調べました。

#!/usr/bin/env ruby1.9
# -*- encoding: utf-8 -*-
require 'rubygems'
require 'open-uri'
require 'hpricot'
require 'rexml/document'

class Checker
  def initialize
    @base = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term="
  end
  
  def prepare gene
    url = @base + gene
    open(url).read
  end

  def count gene
    source =  prepare gene
    doc = REXML::Document.new source
    doc.elements['/eSearchResult/Count'].text.to_i
  end

  def count2 gene
    source =  prepare gene
    doc = Hpricot(source) # !> `&' interpreted as argument prefix
    doc.at("esearchresult > count").inner_text.to_i
  end
  def count3 gene
    source =  prepare gene
    doc = Hpricot(source)
    (doc/"esearchresult > count").first.innerText.to_i
  end
end


c = Checker.new
require 'mybench'
p = proc{ |fn,str| [c.method(fn), str]}
set = proc{ |fn| p.call(fn,"CDK2")}
b = Bench.new
b.add_method(set[:count],set[:count2],set[:count3])
b.run

計測結果

RUBY_VERSION 1.9.0
RUBY_RELEASE_DATE 2008-03-01
RUBY_PLATFORM i686-linux
RUBY_PATCHLEVEL 0
RUBY_REVISION 15664
RUBY_DESCRIPTION ruby 1.9.0 (2008-03-01 revision 15664) [i686-linux]
RUBY_COPYRIGHT ruby - Copyright (C) 1993-2008 Yukihiro Matsumoto

Rehearsal ------------------------------------------
count    0.050000   0.000000   0.050000 (  0.496448)
count2   0.010000   0.000000   0.010000 (  0.441017)
count3   0.010000   0.000000   0.010000 (  0.439024)
--------------------------------- total: 0.070000sec

             user     system      total        real
count    0.020000   0.000000   0.020000 (  0.442338)
count2   0.010000   0.000000   0.010000 (  0.437256)
count3   0.010000   0.000000   0.010000 (  0.462418)

あんまり変わらないのでhpricotを使わないことにしました。