Hatena::ブログ(Diary)

ohacの日記

2009-12-11

dRubyで並列処理

(※12月の1日から25日まで、日替わりで RubyTips を紹介するイベント、 Ruby Advent Calendar jp: 2009 の 11 日目です。昨日は no6v さんでした。明日は id:willnet さんの予定です。)


RubyのThreadは時分割なので並列処理を行いたいときにちょっと困ります。そんなときにはdRubyを使ってみるのはいかがでしょうか。


http://gist.github.com/250118

#!/usr/bin/ruby
require 'drb/drb'
class MonteCarlo
  def initialize(seed)
    srand(seed)
  end
  def dice(n)
    best = rand
    n.times do
      r = rand
      best = r if r < best
    end
    best
  end
end

PROCESSORS = (ARGV[0] || 1).to_i

pids = []
workers = PROCESSORS.times.map do |i|
  uri = "druby://localhost:#{12345 + i}"
  pids << fork { DRb.start_service(uri, MonteCarlo.new(i)); sleep }
  DRbObject.new_with_uri(uri)
end

begin
  n = 5000000 / PROCESSORS
  q = Queue.new
  sleep 0.1
  ts = workers.map do |foo|
    Thread.start(foo) {|f| q.push(f.dice(n))}
  end
  ts.each{|t| t.join}
  p q.size.times.map{q.pop}.min
ensure
  pids.each {|pid| Process.kill(:TERM, pid)}
end

このサンプルコードは500万回の疑似乱数の中から最も0に近い実数を見つけだすというプログラムです。sleep 0.1の部分は見なかったことにしてください。サンプルなので内容はあまり意味がありませんが、要は並列処理したい部分をMonteCarloのdiceの中に書いてあげればいいわけです。このプログラムは以下のように並列処理数を指定して実行します。

$ ruby montecarlo.rb 2

この例では2つのプロセスを並列で動かします。最近のデュアルコアCPUでは2を指定しましょう。コアがもっと多い人は「界王拳4倍!」とか唱えながら4とかを指定するといいでしょう。コアが1つしかない方はヤムチャの気分になってあきらめてください。というのは冗談で、コア数を超えていても一応動きますので試してみてください。


メインのプロセスはforkで生成された子プロセス2つに命令を送り、待つためのスレッドがそれぞれ生成され、joinで終了を待ちます。


結果はQueueに格納され、これを個数分popして取り出し、その中から最小値を取り出して表示して終了します。Queueは便利ですね。


以下はベンチマークです。平均とかは取っていないのでかなり適当ですが。それにしてもやっぱりCore i7は速いですね。こんなことにしかこのPCを活かせていないのが悲しいですが。


Ruby1.8.7

プロセスCoreDuoCore i7
17.284s4.482s
23.882s 2.120s
33.898s 1.417s
43.876s 1.102s
53.695s 1.163s
63.754s 0.997s
73.716s 0.958s
83.666s 0.974s
93.738s 1.029s
103.713s 0.983s
113.905s 0.981s
123.776s 0.952s
133.697s 0.934s
183.816s 0.896s
323.669s 0.907s
644.036s 0.942s
964.643s 0.973s

Ruby1.9.1

プロセスCoreDuoCore i7
14.675s 2.082s
22.677s 1.112s
32.656s 0.791s
42.609s 0.625s
52.746s 0.705s
62.649s 0.656s
72.581s 0.641s
82.626s 0.616s
92.691s 0.646s
102.617s 0.632s
112.619s 0.629s
122.573s 0.633s
162.705s 0.639s
322.619s 0.662s
643.144s 0.625s
963.010s 0.797s

なお、このプログラムlinuxでしか試していませんので、動かなかった場合はがんばって動くようにしてもらえると助かります。また、MacRubyな方はこんなことしなくても普通にスレッドで動かせばよいらしいです。(くやしー!)

ohacohac 2010/03/02 19:58 関係ないけど、ケータイでfoursquareを使うためのサービスを作りました。
と、ここに書くとどうなるかテスト。

投稿したコメントは管理者が承認するまで公開されません。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

Connection: close