2つの答え:
怠惰な答え: ブロッキング書き込みを使用するだけです。EM は、1 つの巨大な文字列ではなく、データの個別のチャンクを既に渡しています。したがって、実装例は少しずれている可能性があります。EM から渡されたチャンクごとに新しい一時ファイルを作成してもよろしいですか? ただし、サンプル コードが意図したとおりに機能していることを前提として説明を続けます。
確かに、怠惰なアプローチは書き込み先のデバイスによって異なりますが、複数の大きなストリームを同時にディスクに書き込もうとすると大きなボトルネックになり、いずれにせよイベント ベースのサーバーを使用する利点が失われます。あらゆる場所でディスク シークをジャグリングすることになり、IO パフォーマンスが低下し、サーバーのパフォーマンスも低下します。一度に多くのことを処理するのは RAM で問題ありませんが、ブロック デバイスと IO スケジューリングを処理し始めると、何をしていてもパフォーマンスのボトルネックに遭遇します。
ただし、他の非 IO 負荷の高い要求に対する低レイテンシー応答が必要な場合に、ディスクへの長時間の書き込みを同時に実行したい場合があると思います。したがって、おそらく良い答えは次のとおりです。
deferを使用します。
require 'rubygems'
require 'tempfile'
require 'eventmachine'
module ExampleServer
def receive_data(data)
operation = proc do
begin
f = Tempfile.new('random')
f.write(data)
ensure
f.close
end
end
callback = proc do
puts "I wrote a file!"
end
EM.defer(operation, callback)
end
end
EventMachine::run {
EventMachine::start_server "127.0.0.1", 8081, ExampleServer
puts 'running example server on 8081'
}
はい、これはスレッドを使用します。この場合、それほど悪くはありません。スレッド間の同期について心配する必要はありません。これは、EM が適切に処理してくれるからです。応答が必要な場合は、ワーカー スレッドの完了時にメインのリアクタ スレッドで実行されるコールバックを使用します。また、ここではIOブロッキングを扱っており、CPUの同時実行性を達成しようとしているのではないため、GILはこのケースでは問題になりません。
ただし、すべてを同じファイルに書き込むつもりだった場合は、遅延に注意する必要があります。これは、スレッドが同時に同じファイルに書き込もうとする可能性が高いため、同期の問題が発生するためです。