J'ai un calcul qui peut être divisé en unités indépendantes et la façon dont je le traite est de créer un nombre fixe de threads, puis de transférer des morceaux de travail à effectuer dans chaque thread. Donc, dans le pseudo-code, voici à quoi ça ressemble
# main thread
work_units.take(10).each {|work_unit| spawn_thread_for work_unit}
def spawn_thread_for(work)
Thread.new do
do_some work
more_work = work_units.pop
spawn_thread_for more_work unless more_work.nil?
end
end
En gros, une fois que le nombre initial de threads est créé, chacun effectue un travail puis continue à prendre des tâches à exécuter de la pile de travail jusqu'à ce qu'il ne reste plus rien. Tout fonctionne bien lorsque j'exécute des tâches dans irb, mais lorsque j'exécute le script à l'aide d'un interprète, les choses ne fonctionnent pas aussi bien. Je ne sais pas comment faire en sorte que le fil principal attende que tout le travail soit terminé. Y at-il une bonne façon de faire cela ou suis-je coincé avec l'exécution de sleep 10 until work_units.empty?
dans le thread principal
Si vous modifiez spawn_thread_for
pour enregistrer une référence à votre Thread
créée, vous pouvez appeler Thread#join
sur le thread pour attendre son achèvement:
x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
x.join # Let the threads finish before
a.join # main thread exits...
produit:
abxyzc
(Volé dans la documentation ri Thread.new
. Voir la documentation ri Thread.join
pour plus de détails.)
Ainsi, si vous modifiez spawn_thread_for
pour enregistrer les références de thread, vous pouvez les rejoindre toutes:
(Non testé, mais devrait donner la saveur)
# main thread
work_units = Queue.new # and fill the queue...
threads = []
10.downto(1) do
threads << Thread.new do
loop do
w = work_units.pop
Thread::exit() if w.nil?
do_some_work(w)
end
end
end
# main thread continues while work threads devour work
threads.each(&:join)
Dans Ruby 1.9 (et 2.0), vous pouvez utiliser ThreadsWait
à partir de stdlib à cette fin:
require 'thread'
require 'thwait'
threads = []
threads << Thread.new { }
threads << Thread.new { }
ThreadsWait.all_waits(*threads)
On dirait que vous reproduisez ce que la bibliothèque Parallel Each ( Peach ) fournit.
Thread.list.each{ |t| t.join unless t == Thread.current }
Vous pouvez utiliser Thread # join
rejoindre (p1 = v1) public
Le thread appelant suspendra l'exécution et exécutera thr. Ne revient pas avant que thr ne quitte ou jusqu'à ce que le nombre de secondes écoulé soit écoulé. Si le délai expire, nil sera renvoyé, sinon thr est renvoyé.
Vous pouvez aussi utiliser Enumerable # each_slice pour parcourir les unités de travail par lots.
work_units.each_slice(10) do |batch|
# handle each work unit in a thread
threads = batch.map do |work_unit|
spawn_thread_for work_unit
end
# wait until current batch work units finish before handling the next batch
threads.each(&:join)
end