用于基准测试的Ruby元编程

时间:2012-03-09 00:35:03

标签: ruby metaprogramming

我有很多混乱的代码,涉及包装基准来执行块中的许多单个方法,记录它们执行的时间,然后将这些信息发送到数据库中供以后参考。这使得代码非常难看。

benchmark_data = Benchmark.realtime do
  begin
    do_something()
   rescue StandardError => e
     log_errors("error occurred")
     raise e
   end
end

write_benchmark_data_to_db(benchmark_data)

此代码基本上复制了我们想要基准测试的每个函数。使用元编程有更好的方法吗?我希望将所有基准测试代码保留在我测量方法的类中。

我在想

class Foo
  def a()
    puts "A"
  end
  ... #repeat for b,c,d,e...
end

f = Foo.new()

add_benchmark(f, [:a,:b,:d]) #records a benchmark event each time f.a,f.b, and f.d are called

有没有人有任何想法?如果可能的话,我想避免使用Foo的子类,因为每个需要基准测试的对象都需要一个子类。

2 个答案:

答案 0 :(得分:0)

这是一个惯用的Ruby解决方案:

def with_stored_benchmark(&block)
  benchmark_data = Benchmark.realtime do
    begin
      block.call
    rescue StandardError => e
      log_errors("error occurred")
      raise e
    end
  end
  write_benchmark_data_to_db(benchmark_data)
end

这是另一种解决方案(种类):

class Module
  def method_bmark_database(*syms)
    syms.each do |sym|
      old=instance_method(sym)
      define_method(sym) do |*args|
        benchmark_data = Benchmark.realtime do
          begin
            old.call(*args)
          rescue StandardError => e
            log_errors("error occurred")
            raise e
          end
        end
        write_benchmark_data_to_db(benchmark_data)
      end
    end
  end
end

这个猴子补丁Module,但你总是把它放在一个模块中并包含它。我不确定它是否有效,因为我现在不在使用Ruby的计​​算机,但它看起来对我来说。


此外,如果您想选择哪些对象进行基准测试:

def log_performance_to_DB(obj, *methods)
  methods.each do |m|
    old=obj.method(m)
    obj.define_singleton_method(m) do |*args|
      benchmark_data = Benchmark.realtime do
        begin
          old.call(*args)
        rescue StandardError => e
          log_errors("error occurred")
          raise e
        end
      end
      write_benchmark_data_to_db(benchmark_data)
    end
  end
end

答案 1 :(得分:0)

为什么不做

之类的事情
class Object
  alias :old_method_missing :method_missing
  def method_missing( meth, *args, &block )
    if benchmark_method? meth
      begin
        old_method_missing meth, *args, &block
      rescue Exception => e
        log_errors( "..." )
        raise e
      end
    else old_method_missing meth, *args, &block
    end
  end
end

我认为这是不言自明的。也许我不明白你的意思,......