Ruby:代理模式,减少方法调用

标签 ruby logging proxy-pattern

如何代理 ruby​​ 记录器并保持性能?

所以,我们工作上有一个要求,很合理。当程序发送信号 HUP 时 日志被刷新并重新启动。

class LocalObject

  attr_accessor :logger

  def initialize context
    # one less method call! Yea! performance++
    @logger = context.logger
  end

  def something
    @logger.info "Hello world"
  end

end

问题是,如果 context.logger 被重置,那么 @logger 仍然指向旧的。

所以,我想我会代理记录器:

class LoggerProxy
  attr_accessor :logger

  def debug *args
    @logger.send :debug, args
  end

  def info *args
    @logger.send :info, args
  end
end

context.logger = LoggerProxy.new
context.logger.logger = Logger.new 'my_file.log'

Signal.trap('HUP') { 
  context.logger.logger = Logger.new 'my_file.log'
}
...
@logger = context.logger
@logger.info "Hello world"

这工作得很好,除了我用 1 个方法调用换成了 2 个方法调用(1 个访问器;返回记录器)。我仍然需要调用 LoggerProxy.:debug, :info, ...,这又调用原始记录器!因此,有 1 个方法调用的地方有 2 个方法调用。

我不想搞乱 Logger 类,或者重载它,因为我想在将来使用其他记录器、syslog、推出我自己的记录器,等等。

有没有办法减少方法调用次数以提高性能?

-丹尼尔

更新:为了回答有关性能的问题,这里是示例测试。

require 'logger'
require 'benchmark';

class MyLogger

  attr_accessor :logger

  def info msg
    @logger.info msg
  end

end

myLogger = Logger.new '/dev/null' # dev null to avoid IO issues
myLoggerProxy = MyLogger.new
myLoggerProxy.logger = myLogger

n = 100000
Benchmark.bm do | benchmarker |
  # plain logger
  benchmarker.report { n.times { myLogger.info 'opps' } }

  # via accessor
  benchmarker.report { n.times { myLoggerProxy.logger.info 'opps' } }

  # via proxy
  benchmarker.report { n.times { myLoggerProxy.info 'opps' } }
end


      user     system      total        real
  1.580000   0.150000   1.730000 (  1.734956)
  1.600000   0.150000   1.750000 (  1.747969)
  1.610000   0.160000   1.770000 (  1.767886)

最佳答案

不要重置记录器本身,而是刷新并重新打开其输出:

logfile = File.open 'my_file.log', 'w+'
context.logger = Logger.new logfile

Signal.trap('HUP') {
  logfile.flush
  logfile.reopen 'my_file.log', 'w+'
}

关于Ruby:代理模式,减少方法调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4319922/

相关文章:

python - 使用 OOP 和代理模式的字符串构造

mysql - 当我运行 rake db :seed, 时,我不断收到 "rake aborted! ActionView::Template::Error: Missing host to link to! "

ruby-on-rails - Rails link_to :format => :xlsx not generating link to . xlsx 路径

ruby - 如何确定所需模块是来自 gem,还是核心模块?

java - 如何在 Spring-boot 中为 REST API 的每个请求创建唯一的 ID?

perl - 如何在 Perl 中跨模块使用 Log4Perl?

php - 如何向 Symfony/Monolog 日志输出添加附加信息(主机、URL 等)?

Ruby 文件强制复制

c++ - 代理容器上的迭代器可能是 “least bad implementation”?

android - 如何使用(智能引用)代理设计模式实现缓存机制?