如何避免连续实例化Ruby线程对象在这个代码



我从来没有使用线程直到现在,但我认为我必须依靠它在这种情况下。我想分别处理cURL命令行的标准输出和标准错误,因为我想将进度指示器(写入标准错误)中的回车符交换为换行符:

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)时在每个循环周期中创建新的线程实例?我认为这是耗时的,我想实例化一次,然后使用它的方法,如停止和运行等

一般来说,您可以在主线程中处理stdout, stderr中的一个,并实例化另一个线程来处理另一个。同时处理多个源是一种常见的做法。

需要注意多线程环境下的内存共享。在您的示例中,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

相关内容

  • 没有找到相关文章

最新更新