オンメモリキャッシュサーバとして druby を試してみた→失敗 - yagihiro outputでなにが起きてるか。
require "drb/drb" front = [] DRb.start_service("druby://:8888", front) puts DRb.uri sleep
require "drb/drb" require "benchmark" DRb.start_service there = DRbObject.new_with_uri "druby://:8888" puts Benchmark::CAPTION puts Benchmark::measure { ARGV[0].to_i.times {|i| there << "hello world #{i}" } }
唯一のRMIは there << "hello world #{i}"ここ。thereはリモートのArrayなので、Array#<<が呼び出される。<<は要素を追加してselfを返すので、Arrayが戻り値。
サーバ側のfrontのArrayはMarshal可能なので戻り値は値渡し(コピー)となり、O(N)の繰り返しでO(N)なのでO(N2)になってしまう。
じゃあどすればよいかというと、frontでDRbUndumpedをextendするか、<<ではなく[]=を使うかするとかかなあ。
require "drb/drb" require "benchmark" DRb.start_service there = DRbObject.new_with_uri "druby://:8888" puts Benchmark::CAPTION puts Benchmark::measure { ARGV[0].to_i.times {|i| there[i] = "hello world #{i}" } }
こんな風にするとリニアっぽい値が出た。
$ ruby b.rb 100 user system total real 0.010000 0.010000 0.020000 ( 0.057440) $ ruby b.rb 1000 user system total real 0.110000 0.050000 0.160000 ( 0.543706) $ ruby b.rb 10000 user system total real 1.080000 0.520000 1.600000 ( 5.447686)
memcachedと比較するならサーバ側はHashが良いんじゃないかと思うんだけど、どうなんだろう。その場合でもクライアントは変更なしでサーバをこうするだけ。
require "drb/drb" front = {} DRb.start_service("druby://:8888", front) puts DRb.uri sleep
結果は似たようなものだった。
$ ruby b.rb 100 user system total real 0.010000 0.010000 0.020000 ( 0.067852) $ ruby b.rb 1000 user system total real 0.110000 0.060000 0.170000 ( 0.523545) $ ruby b.rb 10000 user system total real 1.080000 0.520000 1.600000 ( 5.254644)
まあ、なんで脊髄反射的に原因がわかったかというと、前に自分でもやったことがあるからなんだけどね。
集合への操作はその戻り値をチェックしといた方がよいです > dRuby。結果のクローンが届いてしまってがっかりすることが多いので。