2011-06-27 3 views
11

La journalisation synchrone entraîne une pénalité de performance importante, car elle peut bloquer. Existe-t-il une bibliothèque Ruby autonome qui effectue une journalisation asynchrone (log4r ne semble pas le faire)? Puis-je modifier l'enregistreur de bibliothèque standard pour se connecter de manière asynchrone? Je cherche quelque chose comme AsyncAppender de log4j - mais de préférence une implémentation qui utilise les blocs de code de Ruby pour déplacer le plus de travail possible vers le thread d'arrière-plan.Existe-t-il une bibliothèque de journalisation asynchrone pour Ruby?

+0

Are 'ruby' interprètes de nos jours encore enfilées jambon assez quand il s'agit d'un code multi-thread? Y a-t-il encore un verrou d'interprète géant qui est essentiel au code Ruby natif? Je suis curieux car, à moins que vous n'utilisiez déjà un framework comme [eventmachine] (http://rubyeventmachine.com/) pour forcer _all_ votre IO à être asynchrone, vous ne verrez peut-être aucun avantage à ne faire que l'enregistrement asynchrone . – sarnold

+0

J'utilise habituellement JRuby, donc j'ai de vrais threads Java (je pense) ... –

+0

ooh;) c'est une raison impérieuse d'envisager d'utiliser JRuby, alors. Merci. – sarnold

Répondre

15

Je sais que vous ne devriez pas vraiment répondre à votre question, mais il semble que tout est facile à rubis:

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 
} 

Et pour mon exemple d'enregistrement:

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

Comme valeurs de retour travail, vous pouvez l'utiliser pour à peu près n'importe quoi:

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

Excellent. La nature expressive de Ruby m'étonne constamment. Vous avez mentionné l'utilisation de JRuby, donc vous avez potentiellement de vrais threads mais vous utilisez aussi beaucoup de magie ruby ​​dynamique, alors comment JRuby fait-il face à toutes les astuces dynamiques? Ce serait cool de voir des benchmarks avec JRuby et MRI côte à côte. – davidk01

+0

Bon code! Vous pourriez être mieux en utilisant des fibres/eventmachine. Les threads feront le travail, mais ils sont beaucoup plus lourds en IRM (et à l'avenir dans JRuby) et nécessitent une gestion et une synchronisation. Je pense qu'il existe déjà un streamer de fichiers de machine à événements qui pourrait être proche de ce que vous voulez: http://stackoverflow.com/questions/2749503/what-is-the-best-way-to-read-files-in-an -eventmachine-based-app –

2

Aucune expérience personnelle avec ce:

Le Swiftcore Analogger met en œuvre un système d'enregistrement asynchrone rapide pour les programmes Ruby ainsi que la bibliothèque client pour envoyer des messages de journalisation à la Processus Analogger.

Analogger accepte les journaux provenant de sources multiples et peut avoir plusieurs destinations de journalisation . Actuellement, la connexion à un fichier, à STDOUT ou à STDERR est prise en charge. Une révision future peut également prendre en charge la journalisation vers une destination de base de données .

Analogger dépend eventmachine (http://rubyforge.org/projects/eventmachine) pour fournir le cadre pour les communications réseau, bien que EM est non utilisé pour la bibliothèque cliente.

+0

Cela semble faire la journalisation asynchrone dans un processus séparé entièrement - Je préfère la journalisation en cours de processus (juste sur un thread différent) –

1

Le construit en classe Logger est thread déjà sûr

+0

Je veux que les messages du journal soient écrits sur le disque sur un thread séparé, donc si le bloc d'E/S le bloque, il ne ralentit pas mon thread principal. –

Questions connexes