web-dev-qa-db-ja.com

Rubyスレッドを管理して、すべての作業を完了するにはどうすればよいですか?

独立したユニットに分割できる計算があり、これを処理する方法は、固定数のスレッドを作成し、各スレッドで実行される作業のチャンクを渡すことです。だから擬似コードでここにそれがどのように見えるかです

# 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

基本的に、最初の数のスレッドが作成されると、各スレッドはいくつかの作業を行い、何もなくなるまで作業スタックから実行するものを取り出し続けます。 irbで物事を実行するとすべてが正常に動作しますが、インタープリターを使用してスクリプトを実行すると、物事はあまりうまくいきません。すべての作業が完了するまでメインスレッドを待機させる方法がわかりません。これを行う良い方法はありますか、それともsleep 10 until work_units.empty?メインスレッド

26
David K.

作成したThreadへの参照を保存するようにspawn_thread_forを変更する場合、完了を待機するスレッドで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...

生成する:

abxyzc

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)
15
sarnold

Ruby 1.9(および2.0)では、この目的でstdlibのThreadsWaitを使用できます。

require 'thread'
require 'thwait'

threads = []
threads << Thread.new { }
threads << Thread.new { }
ThreadsWait.all_waits(*threads)
32
esad

Parallel Each( Peach )ライブラリが提供するものを複製しているようです。

3
Hector Castro
Thread.list.each{ |t| t.join unless t == Thread.current }
2
brauliobo

Thread#join を使用できます

join(p1 = v1)public

呼び出しスレッドは実行を一時停止し、thrを実行します。 thrが終了するか、limit秒が経過するまで戻りません。制限時間が切れるとnilが返され、そうでなければthrが返されます。

Enumerable#each_slice を使用して、作業単位をバッチで反復することもできます

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
Hirurg103