私は私のこの問題を解決することにある程度成功しました。同様の問題を抱えている人がこのページを見つけた場合に備えて、詳細と説明を以下に示します。しかし、詳細を気にしない場合は、ここに簡単な答えがあります:
PTY.spawnを次の方法で使用します(もちろん、独自のコマンドを使用します)。
require 'pty'
cmd = "blender -b mball.blend -o //renders/ -F JPEG -x 1 -f 1"
begin
PTY.spawn( cmd ) do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
そして、これが長い答えですが、詳細が多すぎます:
本当の問題は、プロセスがそのstdoutを明示的にフラッシュしない場合、IOを最小化するために、プロセスが完了するまで、stdoutに書き込まれたものは実際に送信されるのではなくバッファリングされることです(これは 明らかにに多くの実装の詳細です) Cライブラリ。スループットが最大化されるように作成されています。stdoutを定期的にフラッシュするようにプロセスを簡単に変更できる場合は、それが解決策になります。私の場合、それはブレンダーだったので、私のような完全な初心者がソースを変更するのは少し怖かったです。
ただし、これらのプロセスをシェルから実行すると、stdoutがシェルにリアルタイムで表示され、stdoutはバッファリングされていないようです。私が信じている別のプロセスから呼び出された場合にのみバッファリングされますが、シェルが処理されている場合、stdoutはバッファリングされていない状態でリアルタイムに表示されます。
この動作は、出力をリアルタイムで収集する必要がある子プロセスとしてのrubyプロセスでも観察できます。次の行を使用して、random.rbというスクリプトを作成するだけです。
5.times { |i| sleep( 3*rand ); puts "#{i}" }
次に、それを呼び出してその出力を返すルビースクリプト:
IO.popen( "ruby random.rb") do |random|
random.each { |line| puts line }
end
期待どおりにリアルタイムで結果が得られないことがわかりますが、その後は一度にすべてが得られます。自分でrandom.rbを実行した場合でも、STDOUTはバッファリングされています。これはSTDOUT.flush
、random.rbのブロック内にステートメントを追加することで解決できます。ただし、ソースを変更できない場合は、これを回避する必要があります。プロセスの外部からフラッシュすることはできません。
サブプロセスがリアルタイムでシェルに出力できる場合は、Rubyを使用してこれをリアルタイムでキャプチャする方法も必要です。そこには。私が信じているRubyコア(とにかく1.8.6)に含まれているPTYモジュールを使用する必要があります。悲しいことに、それは文書化されていません。しかし、幸いなことにいくつかの使用例を見つけました。
まず、PTYとは何かを説明するために、疑似端末の略です。基本的に、rubyスクリプトは、コマンドをシェルに入力したばかりの実際のユーザーであるかのように、サブプロセスに表示されます。したがって、ユーザーがシェルを介してプロセスを開始したときにのみ発生する変更された動作(この場合、STDOUTがバッファリングされていないなど)が発生します。別のプロセスがこのプロセスを開始したという事実を隠すことで、STDOUTがバッファリングされていないため、リアルタイムで収集できます。
子としてrandom.rbスクリプトを使用してこれを機能させるには、次のコードを試してください。
require 'pty'
begin
PTY.spawn( "ruby random.rb" ) do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end