2015-07-06 3 views
0

Я никогда не использовал Thread до сих пор, но я думаю, что я должен полагаться на это в этом случае. Я хотел бы, чтобы обработать стандартный вывод и стандартный поток ошибок завитка командной строки в отдельности, потому что я хочу обменять возврата каретки в индикаторе хода (который записывается поток ошибок) в новой строкой:Как избежать последовательного создания объекта Ruby Thread в этом коде?

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 

Мой вопрос заключается в том могу ли я избежать создания нового экземпляра Thread во время цикла цикла при обработке stdout (stdout.each_char)? Я думаю, что это требует много времени, я хотел бы создать экземпляр один раз, а затем использовать его методы, такие как остановка и запуск и т. Д.

+0

Почему обе эти логические части читают 'stderr.getc' (вторая использует' each_char')? –

+0

Поскольку я испытал, что поток stderr все еще содержит данные, когда stdout уже пуст. – Konstantin

+0

Вам будет гораздо лучше использовать select для управления чтением из нескольких объектов ввода-вывода. –

ответ

0

Как правило, вы можете обрабатывать один из stdout, stderr в основной теме и создавать экземпляр другого потока для обработки другой. Это обычная практика для одновременного обработки нескольких источников.

Вы должны обратить внимание на совместное использование памяти в многопоточном контексте. В вашем случае line, stderr являются общими и изменяются в нескольких потоках без синхронизации, что приведет к непредсказуемому поведению.

В большинстве случаев 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 
+0

Мне нужно изменить возврат каретки \\ r в новые строки \\ n, так как этот код работает в программе CGI, а файл журнала Apache содержит все stderr строка, разделенная на induvidual символов в первом случае, прилагаемом к другой информации (IP, время, реферал), множество строк и размер файла журнала растет очень быстро. Однако он будет содержать отдельные строки во втором случае, когда возврат каретки заменяется символами новой строки. – Konstantin

Смежные вопросы