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.
Où dans le cycle de vie générez-vous le fil? –
@luke_randall: Quand une requête est soumise, je génère un thread à l'intérieur du contrôleur. – bragboy
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