From: Masaki Matsushita Date: 2011-03-10T18:06:53+09:00 Subject: [ruby-dev:43336] [Ruby 1.9 - Bug #4474] 複数のスレッドからトランザクションに入ろうとした場合のPStoreの挙動 Issue #4474 has been updated by Masaki Matsushita. 私も試してみましたが、確かにMutexはDummyMutexと比べて2倍程度遅いようです。 しかし、次のコード require 'benchmark' require 'pstore' pd = PStore.new("foo") #DummyMutex pm = PStore.new("bar", true) #Mutex pd.transaction { pd["hoge"] = 0 } pm.transaction { pm["hoge"] = 0 } N = 1000 Benchmark.bmbm do |x| x.report("DummyMutex") do N.times do pd.transaction { pd["hoge"] += 1 } end end x.report("Mutex") do N.times do pm.transaction { pm["hoge"] += 1 } end end end をruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux]で実行したところ Rehearsal ---------------------------------------------- DummyMutex 0.020000 0.270000 0.290000 ( 0.424386) Mutex 0.080000 0.250000 0.330000 ( 0.468132) ------------------------------------- total: 0.620000sec user system total real DummyMutex 0.100000 0.240000 0.340000 ( 0.476209) Mutex 0.110000 0.210000 0.320000 ( 0.469675) という結果となりました。 トランザクションの出入りに関わる処理全体として見るとあまり大きな差とはなっていないように思えます。 次のコード require 'pstore' p = PStore.new("foo", true) p.transaction { p["hoge"] = 0 } 1000.times do p.transaction { p["hoge"] += 1 } end をプロファイルしたところ、 % cumulative self self total time seconds seconds calls ms/call ms/call name 64.25 1.42 1.42 1001 1.42 1.42 File#truncate 3.62 1.50 0.08 2003 0.04 0.05 Digest::Instance.digest 3.17 1.57 0.07 2003 0.03 0.09 Digest::Class#digest 3.17 1.64 0.07 1001 0.07 1.67 PStore#save_data 3.17 1.71 0.07 1001 0.07 0.20 PStore#load_data 2.26 1.76 0.05 1001 0.05 2.03 Mutex#synchronize (以下略) となっており、Mutexによるロックは時間的に多くを占めるものではないようです。 以上のような結果も併せて、ruby-coreの方にも投稿してみようと思います。 ---------------------------------------- Bug #4474: 複数のスレッドからトランザクションに入ろうとした場合のPStoreの挙動 http://redmine.ruby-lang.org/issues/4474 Author: Masaki Matsushita Status: Closed Priority: Normal Assignee: Category: lib Target version: ruby -v: - PStoreは、initializeの第2引数thread_safeが真であればデータベースの読み書きをMutexで同期するようになっています。 しかし、次のコード require 'pstore' require 'thread' pstore = PStore.new("foo", true) q = Queue.new Thread.start do pstore.transaction do pstore[:hoge] = "fuga" q.push(nil) sleep end end q.pop pstore.transaction do p pstore[:hoge] end を実行すると例外が発生します。 /usr/local/lib/ruby/1.9.1/pstore.rb:321:in `transaction': nested transaction (PStore::Error) from pstore.rb:16:in `
' 以下のコードはpstore.rbの319行目以降から抜粋したものです。 319 def transaction(read_only = false, &block) # :yields: pstore 320 value = nil 321 raise PStore::Error, "nested transaction" if @transaction 322 @lock.synchronize do      (中略) 348 end (中略) 352 end Mutexで保護されたセクションに入る前に、別のトランザクションが実行されていないかどうか調べています。 あるスレッドがトランザクションを実行中に別のスレッドがトランザクションに入ろうとすると、ここで例外が発生します。 thread-safeの定義にも依りますが、これはバグではないでしょうか? -- http://redmine.ruby-lang.org