¿Cómo manejo los hilos ruby para que terminen todo su trabajo?
Tengo un cálculo que se puede dividir en unidades independientes y la forma en que estoy tratando con él ahora es mediante la creación de un número fijo de hilos y luego la entrega de trozos de trabajo a realizar en cada hilo. Así que en pseudo código esto es lo que parece
# 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
Básicamente una vez que se crea el número inicial de subprocesos, cada uno hace algún trabajo y luego sigue tomando cosas que hacer de la pila de trabajo hasta que no queda nada. Todo funciona bien cuando corro cosas en irb pero cuando ejecutar el script usando el intérprete las cosas no funcionan tan bien. No estoy seguro de cómo hacer que el hilo principal espere hasta que todo el trabajo esté terminado. ¿Hay una buena manera de hacer esto o estoy atascado con la ejecución sleep 10 until work_units.empty?
en el hilo principal
5 answers
Si modificas spawn_thread_for
para guardar una referencia a tu Thread
creado, entonces puedes llamar a Thread#join
en el hilo para esperar a que se complete:
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...
Produce:
abxyzc
(Robado de la documentación ri Thread.new
. Vea la documentación de ri Thread.join
para más detalles.)
Entonces, si modificas spawn_thread_for
para guardar las referencias del hilo, puedes unirlas todas:
(No probado, pero debe dar el sabor)
# 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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-05 23:51:35
En ruby 1.9 (y 2.0), puedes usar ThreadsWait
desde el stdlib para este propósito:
require 'thread'
require 'thwait'
threads = []
threads << Thread.new { }
threads << Thread.new { }
ThreadsWait.all_waits(*threads)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-11 18:52:02
Parece que estás replicando lo que proporciona la biblioteca Parallel Each ( Peach).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-05 15:34:10
Thread.list.each{ |t| t.join unless t == Thread.current }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-13 11:49:36
Puedes usar Thread # join
Join (p1 = v1) public
El subproceso que llama suspenderá la ejecución y ejecutará thr. No regresa hasta que thr salga o hasta que hayan pasado los segundos límite. Si el límite de tiempo expira, se devolverá nil, de lo contrario se devolverá thr.
También puede usar Enumerable#each_slice para iterar sobre las unidades de trabajo en lotes
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-11 16:26:34