2012-01-29 3 views
2

J'ai un problème étrange avec le programme aRuby que j'écris.Comment puis-je savoir si une méthode ou une boucle est terminée?

Fondamentalement, l'idée est que le programme fonctionne constamment en arrière-plan. Le programme vérifie l'historique de mon navigateur toutes les 30 secondes et télécharge tous les nouveaux éléments d'historique sur un serveur.

# client.rb 
history = HistoryUploader.new(Chrome) 
# Run everything 
loop do 
    history.run 
    sleep 30 
end 

La partie importante de la classe HistoryUploader ressemble à ceci

class HistoryUploader 
    def run 
    upload_history until local.last_seen_history_item == server.last_seen_history_item 
    end 

    def upload_history 
    # POST batches of history items to the server 
    end 
end 

Le principal problème que je vois avec ce code est que si HistoryUploader.run prend plus de 30 secondes pour terminer (ce qui peut très bien depuis il envoie plusieurs requêtes http), la boucle extérieure dans client.rb va tenter d'appeler à nouveau run et je pourrais obtenir des requêtes parallèles allant au serveur ce qui désorganiserait vraiment les choses.

Est-il possible de bloquer la méthode run à deux reprises jusqu'à ce qu'elle soit terminée?

Répondre

2

Je voudrais utiliser une file d'attente de demandes qui exécute les demandes les unes après les autres. Vous pouvez également placer un simple drapeau booléen à l'intérieur de HistoryUploader, par exemple. @is_uploading:

class HistoryUploader 

    attr_accessor :is_uploading 

    def initialize 
    @is_uploading = false 
    end 

    def run 
    if @is_uploading 
     return 
    end  
    upload_history until local.last_seen_history_item == server.last_seen_history_item 
    end 

    def upload_history 
    @is_uploading = true 
    # POST batches of history items to the server 
    # On uploading finished: 
    @is_uploading = false 
    end 
end 

Si vous voulez vraiment bloquer la boucle principale jusqu'à ce que le téléchargement est terminé, vous pouvez envoyer un fil et d'attendre qu'elle se termine en utilisant rejoindre:

require 'thread' 

t = Thread.new do 
    #post to server 
end 
t.join 
3

Je ne pense pas vous avez le problème que vous pensez avoir. La façon dont vous décrivez votre code est toujours à un seul thread. Vous ne lancez pas un nouveau thread pour faire l'historique.run, ce qui signifie que le sleep 30 ne sera pas exécuté tant que votre méthode history.run ne sera pas retournée. Que vous ayez besoin de faire ce thread dépend du comportement que vous recherchez. Si vous voulez déclencher un autre appel à history.run 30 secondes après la fin de history.run, votre code le fera maintenant. Si vous voulez exécuter cette opération toutes les 30 secondes indépendamment du temps d'exécution de history.run (par exemple, history.run prend 7,5 secondes, vous voulez donc réexécuter la requête en 22,5 secondes), alors une solution threadée est probablement la plus élégant.

Questions connexes