4

RubyMRI1.8.7でのファイル書き込みは完全にスレッドセーフであるように思われます。

例1-完璧な結果:

File.open("test.txt", "a") { |f|
  threads = []
  1_000_000.times do |n|
    threads << Thread.new do
      f << "#{n}content\n"
    end
  end
  threads.each { |t| t.join }
}

例2-完璧な結果(ただし遅い):

threads = []
100_000.times do |n|
  threads << Thread.new do
    File.open("test2.txt", "a") { |f|
      f << "#{n}content\n"
    }
  end
end
threads.each { |t| t.join }

それで、並行性の問題に直面するシナリオを再構築できませんでしたね。

なぜ私がまだここでMutexを使うべきなのか誰かが私に説明してくれたら幸いです。

編集:これは、完全に正常に機能し、同時実行の問題を示さない、もう1つのより複雑な例です。

def complicated(n)
  n.to_s(36).to_a.pack("m").strip * 100
end

items = (1..100_000).to_a

threads = []
10_000.times do |thread|
  threads << Thread.new do
    while item = items.pop

      sleep(rand(100) / 1000.0)
      File.open("test3.txt", "a") { |f|
        f << "#{item} --- #{complicated(item)}\n"
      }

    end
  end
end
threads.each { |t| t.join }
4

1 に答える 1

3

私もエラーを出すことができませんでした。

ここでファイルロックが発生している可能性があります。複数のスレッドが同じファイルに書き込む場合は、次のようにすべて同じファイルオブジェクトを使用する必要があります。

File.open("test.txt", "a") do |fp|
  threads = []
  
  500.times do |time|
    threads << Thread.new do
      fp.puts("#{time}: 1")
      sleep(rand(100) / 100.0)
      fp.puts("#{time}: 2")
    end
  end
  
  threads.each(&:join)
end

この例では、GILによって実際のスレッドのバグからおそらく救われるでしょうが、実際のスレッドと2つの書き込みを使用しているJRubyで何が起こるかは、まったくわかりません。同じことが、実際のスレッドを使用する他のRubyエンジンにも当てはまります。

コードをロックで保護する必要がある場所については、使用しているRubyエンジンに依存する場合は節約する必要があります。または、すべてのRubyエンジンで「機能する」ソリューションをコーディングする必要があります。 、同時実行の問題からあなたを救うための組み込み機能があるかどうかに関係なく。

もう1つの質問は、オペレーティングシステムやファイルシステムがファイルロックによるスレッドバグからあなたを救っているのかどうか、そしてコードがオペレーティングシステムやファイルシステムに依存しない、つまりファイルに依存しないのかどうかです。システムロックにより、ファイルのオープンと書き込みがオペレーティングシステムやファイルシステムによって適切に同期されていることを確認します。

私は手足を踏み出して、他の誰かがどのRubyエンジン、オペレーティングシステム、またはファイルシステムであるかに関係なく、コードが機能し続けることを保証するために、自分の側にもロックを実装することは良い習慣のようだと言います最近のほとんどのRubyエンジン、オペレーティングシステム、およびファイルシステムにはこれらの機能が組み込まれていますが、コードを使用する予定です。

于 2013-02-27T12:23:54.183 に答える