如何管理ruby线程以完成所有工作?

dav*_*k01 24 ruby multithreading threadpool

我有一个可以分成独立单元的计算,现在我正在处理的方法是创建一个固定数量的线程,然后在每个线程中分发要完成的工作块.所以在伪代码中这就是它的样子

# 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
Run Code Online (Sandbox Code Playgroud)

基本上,一旦创建了初始线程数,每个线程都会完成一些工作,然后继续从工作堆中完成工作,直到没有剩下任何东西.当我在irb中运行时,一切正常,但是当我使用解释器执行脚本时,事情并没有那么好用.我不确定如何使主线程等到所有工作完成.有没有一种很好的方法可以做到这一点,或者我坚持sleep 10 until work_units.empty?在主线程中执行

esa*_*sad 32

在ruby 1.9(和2.0)中,您可以使用ThreadsWaitstdlib来实现此目的:

require 'thread'
require 'thwait'

threads = []
threads << Thread.new { }
threads << Thread.new { }
ThreadsWait.all_waits(*threads)
Run Code Online (Sandbox Code Playgroud)

  • 你能解释一下`ThreadsWait.all_waits(*threads)`和`threads.each {| thr | thr.join}`? (4认同)
  • 第二种方式是现代API. (3认同)

sar*_*old 15

如果修改spawn_thread_for为保存对创建的引用Thread,则可以调用Thread#join线程等待完成:

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...
Run Code Online (Sandbox Code Playgroud)

生产:

abxyzc
Run Code Online (Sandbox Code Playgroud)

(从ri Thread.new文档中窃取.有关ri Thread.join更多详细信息,请参阅文档.)

因此,如果您修改spawn_thread_for以保存线程引用,则可以将它们全部加入:

(未经测试,但应该给出味道)

# 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)
Run Code Online (Sandbox Code Playgroud)

  • @ davidk01,当一个'完成'时,为什么要启动另一个帖子?只需在已经运行的线程中获取一个新的工作单元.启动十个线程然后让他们开始从工作队列中吸取工作单元.(有关线程安全的队列实现,请参阅`Queue`类.) (2认同)