2011-06-27 25 views
11

Rejestrowanie synchroniczne wiąże się z dużą karą za wyniki, ponieważ może blokować. Czy istnieje autonomiczna biblioteka Ruby, która wykonuje rejestrację asynchroniczną (wydaje się, że log4r nie działa)? Czy mogę zmodyfikować standardowy program rejestrujący biblioteki, aby logować się asynchronicznie? Szukam czegoś podobnego do log4j: AsyncAppender - ale najlepiej implementacja, która używa bloków kodu Ruby, aby przesunąć jak najwięcej pracy do wątku tła, jak to tylko możliwe.Czy istnieje Asynchronous Logging Library dla Ruby?

+0

Czy 'ruby' tłumaczy te dni nadal dość ham-nawleczone kiedy dochodzi do wielowątkowego kodu? Czy jest jeszcze olbrzymia blokada tłumacza, która jest kluczowym rdzennym kodem Ruby o pojedynczych wątkach? Jestem ciekawy, ponieważ, chyba że już korzystasz z frameworka takiego jak [eventmachine] (http://rubyeventmachine.com/), aby wymusić _all_ twoje IO na asynchroniczne, możesz nie widzieć żadnej korzyści z robienia tylko asynchronicznego rejestrowania . – sarnold

+0

Zwykle używam JRuby, więc mam prawdziwe wątki Java (myślę) ... –

+0

ooh;) To jest ważny powód, aby rozważyć użycie JRuby. Dzięki. – sarnold

Odpowiedz

15

wiem, że nie powinno naprawdę odpowiedzieć na własne pytanie, ale wydaje się, że wszystko jest proste w Ruby

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 
} 

I na moim przykładzie rejestrowania:

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

Jako wartości zwracanych pracować, możesz użyć tego do prawie wszystkiego:

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

Doskonałe. Ekspresyjna natura Ruby nieustannie mnie zadziwia. Wspomniałeś o używaniu JRuby, więc masz potencjalnie prawdziwe wątki, ale używasz również dynamicznej ruby ​​magic, więc jak dobrze JRuby radzi sobie ze wszystkimi dynamicznymi sztuczkami? Byłoby fajnie zobaczyć kilka benchmarków z JRuby i MRI obok siebie. – davidk01

+0

Ładny kod! Lepiej być przy użyciu włókien/eventmachine. Wątki wykonają zadanie, ale są znacznie ważniejsze w MRI (i w przyszłości w JRuby) i wymagają zarządzania i synchronizacji. Myślę, że istnieje już streamer plików maszyn zdarzeń, który może być zbliżony do tego, co chcesz: http://stackoverflow.com/questions/2749503/what-is-the-best-way-to-read-files-in-an -eventmachine-based-app –

2

Nie osobiste doświadczenia z tym:

Swiftcore Analogger implementuje szybki asynchronicznego systemu rejestrowania programów Ruby oraz biblioteki klienta do wysyłania wiadomości z logowaniem do Proces Analogger.

Analogger akceptuje logi z wielu źródeł i może mieć wiele miejsc rejestrowania . Obecnie obsługiwane jest logowanie do pliku, do STDOUT lub do STDERR. Przyszła wersja może również obsługiwać logowanie do docelowego bazy danych .

Analogger zależy od EventMachine (http://rubyforge.org/projects/eventmachine) , aby zapewnić ramy dla komunikacji sieciowej, chociaż EM jest nieużywany do biblioteki klienta.

+0

Wydaje się, że rejestrowanie asynchroniczne odbywa się w oddzielnym procesie - wolę rejestrowanie w trakcie procesu (tylko w innym wątku). –

1

Wbudowany klasy Logger jest już wątku bezpieczne

+0

Chcę, aby komunikaty dziennika były zapisywane na dysku w osobnym wątku, więc jeśli IO blokuje to, nie spowalnia mojego głównego wątku. –