2010-11-30 6 views
2

ルビーロガーをプロキシしてパフォーマンスを維持するにはどうすればよいですか?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" 

これは私が2つのメソッド呼び出しのための1つのメソッド呼び出し(1つのアクセサ;ロガーを返します)取引きを除き、正常に動作します。私はまだLoggerProxy.:debug、:info、...を呼び出さなければなりません。これは元のロガーを呼び出します! Ergo、2つのメソッド呼び出し、そこに1つあった。

私は将来的に他のロガーを使用したいので、Loggerクラスで猿にしたくない、またはそれをオーバーロードします。

パフォーマンス向上のためのメソッド呼び出しの回数を減らす方法はありますか?

-daniel

更新:パフォーマンスについての質問に応じて、ここにサンプルテストです。代わりに、その出力を、フラッシュロガー自体をリセットして再度開くの

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) 
+0

Ohmygoodness。私が間違っていない限り、これはブログとは関係がないので、私は "blogger"タグを削除しました。 –

+0

@ジョナサン:タグリストに "logger"と入力してタブを押すと、リストの上位にある "blogger"が表示されます(98対84)。 –

+0

私は見る!それは理にかなっている。 –

答えて

2

まず:あなたは途中で最適化しているように、あなたの質問にはにおいがします。 を知っている場合にのみ最適化すべきです。コードが低すぎます。 (そして、あなたのベンチマークショーのみの小さな違い)ロガーがこれまでに更新されている場合、あなたはコンテキストごとにプロキシを通知させることができると言いました

class ProxyLogger 
    attr_accessor :logger 

    def initialize(context) 
    context.register(self) 
    end 
end 

class Context 
    attr_accessor :logger 

    def initialize 
    @proxies = [] 
    end 

    def logger=(val) 
    @logger = val 
    @proxies.each { |p| p.logger = val } 
    end 

    def register(proxy) 
    @proxies << proxy 
    end 
end 

をしかし、再び、これは本当に、追加の複雑さの価値は思えません。

(関連性:)

+0

時期尚早の最適化の発言のために+1。また、IMOでは、メソッドコールを排除するためにコードを複雑にしている場合は、おそらくRuby以外の言語を考慮する必要があります。 –

4

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

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

問題は将来、私は何かを追加したい、それは再開機能を持たないかもしれない。 Say、syslog ... – Daniel

関連する問題