我编写了一个小型基准测试类来测试我的开发代码。目前我必须将类添加到每个方法的开头和结尾。是否可以预先添加、动态添加,这样我就不必弄乱我的代码了?
class ApplicationController
before_filter :init_perf
after_filter :write_perf_results_to_log!
def init_perf
@perf ||= Perf.new
end
def write_perf_results_to_log!
@perf.results
end
end
class Products < ApplicationsController
def foo
@perf.log(__methond__.to_s)
caculation = 5 *4
@perf.write!
end
def bar
@perf.log(__methond__.to_s)
caculation = 1 / 5
@perf.write!
end
end
这是 Perf 类。它位于服务文件夹中。
class Perf
def initialize
@results = []
end
def log(note)
@start = Time.now
@note = note
end
def write!
if @results.find {|h| h[:note] == @note } # Update :sec method exists in results
@results.select { |h| h["note"] == @note; h[":sec"] = (Time.now - @start).round(3) }
else # Add new Hash to results
@results << { :note => @note, :sec => (Time.now - @start).round(3) }
end
end
def results
content = "
PERFORMANCE STATISTICS!
"
@results.each do |r|
content += r[:note] + " " + r[:sec].to_s + "
"
end
content += "
"
Rails.logger.info content
end
end
最佳答案
在一般计算术语中,您想要做的事情称为 code instrumentation .有几种方法可以实现这一点,但是这里有一个使用元编程的(粗略的)示例:
首先定义一个我们将用于注入(inject)检测代码的新方法:
class ApplicationController
def self.instrument_methods(*methods)
methods.each { |m|
# Rename original method
self.send(:alias_method, "#{m}_orig", m)
# Redefine old method with instrumentation code added
define_method m do
puts "Perf log #{m}"
self.send "#{m}_orig"
puts "Perf write"
end
}
end
end
使用方法:
class Product < ApplicationController
def foo
puts "Foo"
end
def bar
puts "Bar"
end
# This has to be called last, once the original methods are defined
instrument_methods :foo, :bar
end
然后:
p = Product.new
p.foo
p.bar
将输出:
Perf log foo
Foo
Perf write
Perf log bar
Bar
Perf write
以下是检测 ruby 代码和衡量性能的一些其他方法:
http://ruby-prof.rubyforge.org/
http://www.igvita.com/2009/06/13/profiling-ruby-with-googles-perftools/
关于ruby-on-rails - Ruby/Rails : Prepend, 将代码附加到所有方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14396035/