1

今までスレッドを使ったことがなかったのですが、今回はこれに頼らざるを得ないと思います。cURL コマンド ラインの stdout と stderr を別々に処理したいのは、プログレス インジケーター (stderr に書き込まれる) のキャリッジ リターンを改行に交換したいからです。

require "open3"
cmd="curl -b cookie.txt #{url} -L -o -"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|

  pid = wait_thr.pid 

  # I have to process stdout and stderr at the same time but
#asyncronously, because stdout gives much more data then the stderr
#stream. I instantiate a Thread object for reading the stderr, otherwise 
#"getc" would block the stdout processing loop.

  c=nil
  line=""
  stdout.each_char do |b| 
       STDOUT.print b

       if c==nil then
         c=""
         thr = Thread.new { 
         c=stderr.getc 
         if c=="\r" || c=="\n" then 
            STDERR.puts line 
            line=""
         else
          line<<c
         end
         c=nil
        }
  end

  #if stderr still holds some output then I process it:
  line=""
  stderr.each_char do |c|

         if c=="\r" || c=="\n" then 
            STDERR.puts line 
            line=""
         else
          line<<c
         end
  end

  exit_status = wait_thr.value.exitstatus 
  STDERR.puts exit_status

end #popen3

私の質問は、stdout (stdout.each_char) を処理するときに、ループ サイクルごとに新しい Thread インスタンスを作成しないようにするにはどうすればよいですか? 時間がかかると思います。一度インスタンス化してから、停止や実行などのメソッドを使用したいと思います.

4

1 に答える 1

0

通常、stdoutメインstderrスレッドで の 1 つを処理し、別のスレッドをインスタンス化してもう 1 つのスレッドを処理できます。これは、複数のソースを同時に処理する一般的な方法です。

マルチスレッド コンテキストでのメモリ共有に注意する必要があります。あなたの場合、linestderr同期せずに複数のスレッドで共有および変更されているため、予期しない動作が発生します。

ほとんどの場合、Ruby が行末を処理します。\rここで\n手動で, を処理する必要はあまりありません。

require "open3"
cmd="curl -b cookie.txt #{url} -L -o -"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  pid = wait_thr.pid

  stdout_thread = Thread.new do
    # process stdout in another thread
    # you can replace this with the logic you want, 
    # if the following behavior isn't what you want
    stdout.each_line do |line|
      puts line
    end
  end

  # process stderr in the main thread
  stderr.each_line do |line|
    STDERR.puts line
  end

  # wait the stdout processing to be finished.
  stdout_thread.join
end
于 2015-07-06T16:38:35.310 に答える