tanamonの稀に良く書く日記

KEEP CALM AND DRINK BEER

Rubyでマルチスレッド

Rubyでマルチスレッドなプログラムを簡単に書けるようにするクラスを作ってみた。
それっぽく動いているけど、僕はRuby力が弱いので合っているのかはわからない。


以下は、特定のディレクトリ以下のファイルを総なめして中身を確認する例。

test.rb

require 'thread_worker'

start = Time.now()

ThreadWorker.new(20) do |worker|
  dir = 'C:/apache-wicket-1.4-rc2/**/*.java'
  Dir::glob(dir) do |path|
    worker.push() do
      File.open(path) do |file|
        words = file.read.split(/\s+/m)
        puts "#{words.length.to_s.rjust(8)} #{path}"
      end
    end
  end
end
puts "#{Time.now()-start}sec"

worker.push()以降はThreadWorker.new()の引数の値分だけ並列で動きます。
この例の場合、単一スレッド処理と比較すると4倍速ぐらいになった。

thread_worker.rb

require 'thread'

class ThreadWorker
  def initialize(num)
    @queue = Queue.new()
    @workers = ThreadGroup.new()

    num.times do
      @workers.add(
        Thread.new() do
          loop do
            @queue.pop().call()
          end
        end
      )
    end

    if block_given? then
      yield(self)
      stop()
    end
  end

  def push(&block)
    @queue.push(block)
  end

  def stop()
    until @queue.empty? do
      sleep(1)
    end

    (@workers.list - [Thread.current]).each do |t|
      t.join(1)
    end
  end

end