Почему open4 не может читать из stdout, когда программа ожидает ввода stdin? - PullRequest
2 голосов
/ 12 июля 2010

Я использую гем open4 и у меня проблемы с чтением из стандартного вывода порожденных процессов. У меня есть программа ruby, test1.rb:

print 'hi.' # 3 characters
$stdin.read(1) # block

И еще одна программа ruby ​​в том же каталоге, test2.rb:

require 'open4'

pid, stdin, stdout, stderr = Open4.popen4 'ruby test1.rb'
p stdout.read(2) # 2 characters

Когда я запускаю вторую программу:

$ ruby test2.rb

Он просто сидит навсегда, ничего не печатая. Почему это происходит, и что я могу сделать, чтобы остановить это?

Ответы [ 3 ]

2 голосов
/ 16 июля 2010

Мне нужно было изменить test1.rb на это. Я не знаю почему.

print 'hi.' # 3 characters
$stdout.flush
$stdin.read(1) # block
2 голосов
/ 31 октября 2014

По умолчанию все, что вы print выводите на стандартный вывод или в другой файл, записывается в буфер Ruby (или в стандартную библиотеку C, которая находится под Ruby).Содержимое буфера передается в ОС, если происходит одно из следующих событий:

  • Буфер заполнен.
  • Вы закрываете стандартный вывод.
  • У вас естьнапечатал последовательность новой строки (`\ n ')
  • Вы вызываете flush явно.

Для других файлов flush также выполняется и в других случаях, например ftell.

Если вы переведете stdout в небуферизованный режим ($stdout.sync = true), буфер не будет использоваться.

stderr по умолчанию не буферизован.Причиной выполнения буферизации является эффективность: агрегирование выходных данных в буфере может сохранить много системных вызовов (обращений к операционной системе).Системные вызовы очень дорогие : они занимают сотни или даже тысячи циклов ЦП.Избегание их с небольшим количеством кода и некоторыми буферами в пространстве пользователя приводит к хорошему ускорению.

Хорошее чтение при буферизации: Почему printf не сбрасывается после вызова, если символ новой строки не находится в форматестрока

1 голос
/ 12 июля 2010

Я не эксперт в процессе.

С первого взгляда на документ API последовательность использования open4 выглядит следующим образом: сначала отправьте текст в stdin, затем закройте stdin и, наконец, прочитайте текст из stdout.

Итак. Вы можете test2.rb, как это

require 'open4'

pid, stdin, stdout, stderr = Open4.popen4 'ruby test1.rb'
stdin.puts "something" # This line is important
stdin.close # It might be optional, open4 might close itself.
p stdout.read(2) # 2 characters
...