Ruby: чтение больших данных из stdout и stderr внешнего процесса в Windows - PullRequest
4 голосов
/ 11 января 2011

Привет, все,

Мне нужно запустить потенциально длительный процесс из Ruby 1.9.2 в Windows, а затем перехватить и проанализировать данные из стандартного вывода и ошибки внешнего процесса.Каждому может быть отправлено большое количество данных, но меня интересует только одна строка за раз (не захватывая и не сохраняя весь вывод).

После небольшого исследования я обнаружил, что Open3 class позаботится о выполнении процесса и даст мне IO объектов, связанных со стандартным выводом процесса и ошибкой (через popen3 ).

Open3.popen3("external-program.bat") do |stdin, out, err, thread|
  # Step3.profit() ?
end

Однако я не уверен, как непрерывно читать из обоих потоков, не блокируя программу.Поскольку вызов IO#readlines на out или err, когда отправлено много данных, приводит к ошибке выделения памяти, я пытаюсь постоянно проверять оба потока на наличие доступных входных данных, но мне не везет ни с одним из моихреализации.

Заранее благодарим за любые советы!

1 Ответ

8 голосов
/ 12 января 2011

После множества попыток проб и ошибок я в конечном итоге придумал использовать два потока, по одному для чтения из каждого потока (generator.rb - это всего лишь сценарий, который я написал для вывода данных в стандартный поток вывода и ошибки):

require 'open3'

data = {}

Open3.popen3("ruby generator.rb") do |stdin, out, err, external|
  # Create a thread to read from each stream
  { :out => out, :err => err }.each do |key, stream|
    Thread.new do
      until (line = stream.gets).nil? do
        data[key] = line
      end
    end
  end

  # Don't exit until the external process is done
  external.join
end

puts data[:out]
puts data[:err]

Он просто выводит последнюю строку, отправленную на стандартный вывод и ошибку вызывающей программой, но, очевидно, может быть расширен для выполнения дополнительной обработки (с различной логикой в ​​каждом потоке).Метод, который я использовал до , я наконец-то придумал, что привело к некоторым сбоям из-за условий гонки;Я не знаю, уязвим ли этот код, но мне еще не приходилось сталкиваться с подобной ошибкой.

...