2010-08-14 3 views
16

L'appel de Thread.join bloque le thread en cours (principal). Toutefois, ne pas appeler les résultats de jointure dans tous les threads générés à être supprimés lorsque le thread principal se ferme. Comment peut-on engendrer des fils d'enfants persistants dans Ruby sans bloquer le fil principal?Thread.join bloque le thread principal

Voici une utilisation typique de join.

for i in 1..100 do 
    puts "Creating thread #{i}" 
    t = Thread.new(i) do |j| 
    sleep 1 
    puts "Thread #{j} done" 
    end 
    t.join 
end 
puts "#{Thread.list.size} threads" 

Cela donne

  Creating thread 1 
    Thread 1 done 
    Creating thread 2 
    Thread 2 done 
    ... 
    1 threads 

mais je cherche comment obtenir ce

 
    Creating thread 1 
    Creating thread 2 
    ... 
    101 threads 
    Thread 1 done 
    Thread 2 done 
    ... 

Le code donne la même sortie dans les deux Ruby 1.8.7 et 1.9.2

Répondre

18

Vous accumulez simplement les fils dans un autre récipient, puis les join un par un après qu'ils ont tous été créés:

my_threads = [] 
for i in 1..100 do 
    puts "Creating thread #{i}" 
    my_threads << Thread.new(i) do |j| 
     sleep 1 
     puts "Thread #{j} done" 
    end 
end 
puts "#{Thread.list.size} threads" 

my_threads.each do |t| 
    t.join 
end 

Vous ne pouvez pas lier aussi le fil à la i variable car i est constamment remplacé, et votre sortie sera de 100 lignes de "Thread 100 done"; Au lieu de cela, vous devez le lier à une copie de i, que j'ai habilement nommé j.

+0

Oui, cela fonctionne. J'aurais pensé que Ruby aurait un moyen de gérer cela implicitement au lieu d'avoir à suivre les threads et à effectuer un appel de jointure à la fin. Et oui, je ne devrais pas utiliser le global i dans chaque thread. Trucs de base. Merci pour la solution propre. Je vais mettre à jour le code. – Alkaline

+5

Dans Ruby 1.9, les paramètres de bloc sont toujours locaux, vous n'avez donc pas besoin de renommer la variable. Vous obtiendrez un avertissement, cependant. (* Variable 'i' ombre variable externe * ou quelque chose comme ça.) –

6

Vous devez joindre les threads en dehors de la boucle.

for i in 1..100 do 
    puts "Creating thread #{i}" 
    t = Thread.new(i) do |mi| 
    sleep 1 
    puts "Thread #{mi} done" 
    end 
end 

# Wait for all threads to end 
Thread.list.each do |t| 
    # Wait for the thread to finish if it isn't this thread (i.e. the main thread). 
    t.join if t != Thread.current 
end 
Questions connexes