2011-06-27 11 views
11

El registro síncrono incurre en una gran penalización de rendimiento ya que puede bloquear. ¿Hay una biblioteca independiente de Ruby que realice el registro asincrónico (log4r no parece)? ¿Puedo modificar el registrador de la biblioteca estándar para que se registre de manera asíncrona? Estoy buscando algo como log4j's AsyncAppender, pero preferiblemente una implementación que hace uso de los bloques de código de Ruby para cambiar tanto trabajo como sea posible.¿Hay una biblioteca de registro asincrónico para Ruby?

+0

son 'intérpretes ruby' estos días todavía bastante desjarretaron cuando se trata de código multihilo? ¿Todavía hay un bloqueo de intérprete gigante que codifica Ruby nativo de un único subproceso? Tengo curiosidad porque, a menos que ya estés usando un framework como [eventmachine] (http://rubyeventmachine.com/) para forzar que _todo_ tu IO sea asincrónico, es posible que no veas ningún beneficio al hacer solo el registro asincrónico . – sarnold

+0

Suelo usar JRuby, así que tengo hilos de Java reales (creo) ... –

+0

ooh;) esa es una razón de peso para considerar usar JRuby, entonces. Gracias. – sarnold

Respuesta

15

Sé que en realidad no debería responder a su propia pregunta, pero parece que todo es fácil en rubí:

require 'thread' 
require 'singleton' 
require 'delegate' 
require 'monitor' 

class Async 
    include Singleton 

    def initialize 
    @queue = Queue.new 
    Thread.new { loop { @queue.pop.call } } 
    end 

    def run(&blk) 
    @queue.push blk 
    end 
end 

class Work < Delegator 
    include MonitorMixin 

    def initialize(&work) 
    super work; @work, @done, @lock = work, false, new_cond 
    end 

    def calc 
    synchronize { 
     @result, @done = @work.call, true; 
     @lock.signal 
    } 
    end 

    def __getobj__ 
    synchronize { @lock.wait_while { [email protected] } } 
    @result 
    end 
end 

Module.class.class_exec { 
    def async(*method_names) 
    method_names.each do |method_name| 
     original_method = instance_method(method_name) 
     define_method(method_name) do |*args,&blk| 
     work = Work.new { original_method.bind(self).call(*args,&blk) } 
     Async.instance.run { work.calc } 
     return work 
     end 
    end 
    end 
} 

Y para mi ejemplo de registro:

require 'Logger' 
class Logger 
    async :debug 
end 
log = Logger.new STDOUT 
log.debug "heloo" 

Como valores de retorno trabajo, puede usar esto para casi cualquier cosa:

require "test/unit" 
class ReturnValues < Test::Unit::TestCase 
    def do_it 
    5 + 7 
    end 
    async :do_it 
    def test_simple 
    assert_equal 10, do_it - 2 
    end 
end 
+0

Excelente. La naturaleza expresiva de Ruby constantemente me sorprende. Mencionaste usar JRuby para que potencialmente tengas hilos reales pero también estás usando mucha magia dinámica de rubí. ¿Qué tan bien JRuby se enfrenta a todos los trucos dinámicos? Sería genial ver algunos puntos de referencia con JRuby y MRI uno al lado del otro. – davidk01

+0

Buen código! Tal vez sea mejor usar fibras/eventomaquina. Los hilos harán el trabajo, pero son mucho más pesados ​​en MRI (y en el futuro en JRuby) y requieren gestión y sincronización. Creo que ya hay un transmisor de archivos de máquina de evento que podría estar cerca de lo que desea: http://stackoverflow.com/questions/2749503/what-is-the-best-way-to-read-files-in-an -eventmachine-based-app –

2

Sin experiencia personal con que:

El Swiftcore Analogger implementa un sistema rápido asíncrono tala para los programas de Ruby, así como la biblioteca de cliente para el envío de mensajes de registro a la Proceso analógico.

Analogger aceptará registros de múltiples fuentes y puede tener múltiples destinos de registro . Actualmente, se admite el inicio de sesión en un archivo, en STDOUT o en STDERR. Una futura revisión también puede admitir el registro en un destino de base de datos .

Analogger depende de EventMachine (http://rubyforge.org/projects/eventmachine) de establecer un marco para las comunicaciones de red, aunque EM es no se utilizan para la biblioteca cliente.

+0

Esto parece hacer el registro asincrónico en un proceso separado por completo. Prefiero el registro en proceso (solo en un hilo diferente) –

1

El construido en la clase Logger ya está seguro para subprocesos

+0

Quiero que los mensajes de registro se escriban en el disco en un hilo separado, por lo que si IO bloquea no ralentiza mi hilo principal. –

Cuestiones relacionadas