2010-10-08 16 views
3

J'essaye d'engendrer un fil dans Rails. Je ne suis généralement pas à l'aise avec les threads, car je devrai avoir une connaissance approfondie du cycle de demande/réponse de Rails, mais je ne peux pas éviter d'en utiliser un car ma requête expire.Filetage dans les rails - les paramètres [] persistent-ils?

Afin d'éviter les délais, j'utilise un thread dans une requête. Ma question ici est simple. Le thread que j'ai utilisé accède à une variable params [] à l'intérieur. Et les choses semblent fonctionner maintenant. Je veux savoir si c'est juste? Je serais heureux si quelqu'un peut faire la lumière sur l'utilisation de Threads in Rails pendant le cycle de demande/réponse.

[Démarrage d'une prime]

+0

Où dans le cycle de vie générez-vous le fil? –

+0

@luke_randall: Quand une requête est soumise, je génère un thread à l'intérieur du contrôleur. – bragboy

+0

Si vous déclenchez un thread pour effectuer un processus qui entraîne une demande trop longue, vous pouvez rechercher quelque chose comme 'delayed_job' pour exécuter des tâches de manière asynchrone en arrière-plan. – Shadwell

Répondre

5

La réponse courte est oui, mais seulement dans une certaine mesure; la liaison dans laquelle le fil a été créé persistera. Les params existeront toujours seulement si personne (y compris Rails) ne fait tout son possible pour modifier ou supprimer le hash params. Au lieu de cela, ils s'appuient sur le garbage collector pour nettoyer ces objets. Puisque le thread a accès au contexte courant (appelé le "binding" dans Ruby) quand il a été créé, toutes les variables qui peuvent être atteintes depuis cette portée (effectivement l'état entier quand le thread a été créé) ne peuvent pas être supprimées par la poubelle collectionneur. Cependant, comme l'exécution continue dans le thread principal, les valeurs des variables dans ce contexte peuvent être modifiées par le thread principal, ou même par le thread que vous avez créé, s'il peut y accéder. C'est le bénéfice - et la chute - des threads: ils partagent la mémoire avec tout le reste.

Vous pouvez émuler un environnement très similaire à Rails pour tester votre problème, en utilisant une fonction en tant que telle: http://gist.github.com/637719. Comme vous pouvez le voir, le code imprime toujours 5.

Cependant, ce n'est pas la bonne façon de procéder. La meilleure façon de transmettre des données à un fil est de passer à Thread.new, comme ceci:

# always dup objects when passing into a thread, else you really 
# haven't done yourself any good-it would still be the same memory 
Thread.new(params.dup) do |params| 
    puts params[:foo] 
end 

De cette façon, vous pouvez être sûr que toutes les modifications à params n'affectera pas votre fil. La meilleure pratique est de seulement utiliser les données que vous transmettez à votre thread de cette façon, ou les choses que le thread lui-même créé. S'appuyer sur l'état du programme en dehors du thread est dangereux. Comme vous pouvez le voir, il y a de bonnes raisons pour que cela ne soit pas recommandé. La programmation multithread est dur, même dans Ruby, et en particulier lorsque vous traitez avec autant de bibliothèques et de dépendances que celles utilisées dans Rails. En fait, Ruby semble simplifier les choses, mais c'est un piège. Les bugs que vous rencontrerez sont très subtils; ils vont arriver "au hasard" et seront très difficiles à déboguer. C'est pourquoi des éléments tels que Resque, Delayed Job et d'autres bibliothèques de traitement en arrière-plan sont largement utilisés et recommandés pour les applications Rails, et je recommande la même chose.

1

La question est plus ne rails maintiennent la demande d'ouverture tandis que le fil est en cours d'exécution que persiste-la valeur.

Il ne va pas persister la valeur dès que la demande se termine et je ne recommanderais pas non plus de maintenir la demande ouverte sauf s'il y a un réel besoin. Comme d'autres utilisateurs l'ont dit, certaines choses sont mieux dans un travail retardé. Cela dit, nous avons utilisé le threading plusieurs fois pour interroger plusieurs sources simultanément et réduire le temps de réponse d'une application (uniquement pour les administrateurs, donc pas besoin de temps de réponse rapide) et si la mémoire est correcte le thread peut garder la demande ouverte si vous appelez join à la fin et attendez que chaque thread se termine avant de continuer.