Ruby: чтение больших данных из stdout и stderr внешнего процесса в Windows

Всем привет,

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

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

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

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

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


person Michelle Tilley    schedule 11.01.2011    source источник
comment
Вы можете указать версию Ruby? Open3 не работает в 1.8.7 и вместо него потребуется гем win32-open3.   -  person Luis Lavena    schedule 11.01.2011
comment
Руби 1.9.2. Обновление вопроса.   -  person Michelle Tilley    schedule 12.01.2011


Ответы (1)


После множества различных проб и ошибок я в конце концов придумал использовать два потока, по одному для чтения из каждого потока (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]

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

person Michelle Tilley    schedule 11.01.2011