【Ruby】スレッド。全てのスレッド(非main)の終了を待つ、ファイルの並列読み出し
全てのスレッド(非main,current)の終了を待つ
def join_all main = Thread.main current = Thread.current all = Thread.list p all all.each{|t| t.join unless t==current || t==main} end Thread.new do sleep(1) Thread.new do sleep(1) p "thred thread" end join_all p "thread" end join_all p "main"
■実行結果
[#<Thread:0x49d148 run>, #<Thread:0x307b900 run>] [#<Thread:0x49d148 sleep>, #<Thread:0x307b900 run>, #<Thread:0x307b420 run>] "thred thread" "thread" "main"
mainメソッドが終了すると実行が停止してしまう
n = 1 while n<=3 Thread.new{p n} n += 1 end
■実行結果
(からっぽ)
なぜかというと、while内でThreadが作成される前にmainメソッドが終了したから。
mainメソッドを終わらせないと、予想通りの結果になる。
n = 1 while n<=3 Thread.new{p n} n += 1 end loop do end
■実行結果
4 4 4
上記の通り、スレッド間で変数へのアクセスが共有できるため、
変数nはスレッドセーフではない。
スレッドセーフにしたいときは、単にブロックを使えば解決できる。
n = 1 while n<=3 Thread.new(n){|x|p x} n += 1 end loop do end
■実行結果
1 2 3
もしくはイテレーターを使うと、外側のスレッド内でプライベートなので
ブロック実行中に値が変わることはない。
3.times do |i| Thread.new{sleep(1); p i} end loop do end
■実行結果
1 0 2
0 2 1
スレッドによる並列処理なので、順序性は保障されない。
ファイルの並列読み出し
def conread(filenames) h={} filenames.each do |filename| h[filename] = Thread.new do File.open(filename){|f| f.read} end end h.each do |filename, thread| begin h[filename] = thread.value rescue h[filename] = $! #<= 最後に起きた例外のオブジェクト end end end dir = File.dirname(__FILE__) + File::SEPARATOR filenames=[dir+"data1.txt", dir+"data2.txt", dir+"data3.txt"] p conread(filenames)
■実行結果
{"C:/Users/HOGE_ADMIN/Desktop/net/data1.txt"=>"hogedata1", "C:/Users/HOGE_ADMIN/Desktop/net/data2.txt"=>"hogedata2", "C:/Users/HOGE_ADMIN/Desktop/net/data3.txt"=>"hogedata3"}