¿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

Author: davidk01, 2011-06-05

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)
 13
Author: sarnold,
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)
 31
Author: esad,
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).

 3
Author: Hector Castro,
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 }
 1
Author: brauliobo,
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
 0
Author: Hirurg103,
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