More than 1 year has passed since last update.

このエントリは パーフェクトRuby Advent Calendar の 20 日目のエントリです

はじめに

みなさん パーフェクトRuby はもう読みましたよね。わしも読んだ。
今までは プログラミング言語 Ruby を傍らに置いてコードを書いていたんですが、最近は パーフェクトRuby も一緒に置いてあります。

さて、600ページを超えるボリュームで、Ruby での開発に必要な事はだいたい載ってるパーフェクトRuby を既に読み終わって手持ち無沙汰になってる人、いますよね?そんなあなたに、次に読む本を1冊ご紹介したいと思います。

dRubyによる分散・Webプログラミング

dRubyによる分散・Webプログラミング という本があるんですが、とても面白いです。日本語で書かれた書籍ですが、後に英語訳版が出版されるという技術書としては珍しい書籍です。
dRuby は Ruby に 標準添付されている 便利なライブラリです。ざっくりと説明すると、別プロセスが持っているオブジェクトに TCP 経由でアクセスして、手元で使うのと変わらぬ感覚で使えてしまうというものです。

マルチプロセスな処理って難しい

例えば、独立した処理の結果を順番に印字しようと思ったときに、子プロセスに処理を分散させようとして下のようなプログラムを書いてみたとします。

multi_process.rb
# 共有するパイプ
reader, writer = IO.pipe

# 適当な処理をする10個のプロセス
10.times do |n|
  index = n
  fork do
    reader.close
    result = rand(5)
    sleep result
    writer.puts "#{index},#{result}"
  end
end

writer.close
Process.waitall
puts reader.read
結果
1,1
4,1
2,2
9,2
3,3
5,37,3

0,4
6,4
8,4

6行目で意図しない感じになってますね。これじゃあ、パースしてソートとか出来ない...
複数のプロセスから同時にパイプへの書き込みがあったときに、排他的ロックみたいなことが出来てないのが原因でしょうか。パイプよりもうちょっと高級なものを使わないといけない気がしますね。

dRuby でマルチプロセスなプログラムを書いてみる

そこで、パイプの代わりに dRuby のサーバープロセスを使って書いてみます

multi_process_by_drb.rb
require 'drb/drb'

URI = 'druby://localhost:33333'

# データ収集サーバー
server_pid = fork do
  DRb.start_service(URI, Array.new)
  sleep
end

# 適当な処理をする10個のプロセス
pids = []
10.times do |n|
  index = n
  pids << fork do
    DRb.start_service
    result = rand(5)
    sleep result
    DRbObject.new_with_uri(URI)[index]= result
  end
end

# 適当な処理たちが全部終わるのを待つ
pids.each do |pid|
  Process.waitpid(pid)
end

# 子プロセスを立ち上げた順に結果を取り出し
DRb.start_service
DRbObject.new_with_uri(URI).each_with_index do |result, index|
  puts "#{index},#{result}"
end

# データ収集サーバープロセスを殺害
Process.kill("HUP", server_pid)
結果
0,3
1,3
2,0
3,2
4,0
5,3
6,2
7,1
8,2
9,0

うまくいった感じがしますね。ただ、なんでうまくいくのかについては、いまいち理解してません。dRuby本の『5.3.1 排他制御』(p.82) に書いてあるっぽいですが難しくて、もう少し勉強が必要です。ここら辺を理解できるようになると次の世界への扉が開く気がします。

このプログラムは子プロセスが適当な秒数 sleep してるだけなので大したこと無いんですが、ちゃんとゴリゴリ計算するような仕事を与えてやると、マルチコアプロセッサの各コアが熱くなって楽しいです。でも調子にのって fork しすぎると死ぬので、どれくらいまでなら fork しても大丈夫なのか、ちゃんと基礎的な勉強をしたいところです。

One more thing

実はこの記事を書くにあたって参考にした本がもう一冊あります。なるほどUnixプロセス ― Rubyで学ぶUnixの基礎 という電子書籍です。 パーフェクトRuby の p.223 〜 p.224 で解説している Process について深く掘り下げた内容です。わしにとっては dRuby 本の副読本のような位置づけで、併せて読むと理解が深まる気がします。

まとめ

プロセッサのコアがどんどん増えていく今日この頃、皆様いかがお過ごしでしょうか。また、金にものを言わせればいくらでも計算資源が増やせる時代をどうやって生き抜いていますか。何をそんなに計算することがあるんだ、と思うかもしれません。わしもそう思う。
せっかく沢山の資源があるんだから、それらを束ねてドッカンと仕事をさせてみたい。しかもお手軽に。と思ったとき、dRuby があなたを見つめているかもしれません。

異常です。