ruby IO.gets читает из буфера? - PullRequest
1 голос
/ 11 января 2020

Может кто-нибудь объяснить мне, как pipe.gets работает в этом случае? такое объект ввода-вывода (в данном примере труба), буферизирующий вывод? Как получается, что я могу потратить время на чтение вывода из stdout, используя «gets»? Я даже заснул там, прежде чем прочитать gets, чтобы убедиться, что я не сумасшедший.

def run_script(commands)
      raw_output = nil
      IO.popen("./db", "r+") do |pipe|
        commands.each do |command|
          pipe.puts command
        end

        pipe.close_write

        # Read entire output
        raw_output = pipe.gets(nil)
      end
      raw_output.split("\n")
    end

1 Ответ

2 голосов
/ 11 января 2020

Параметры pipe.sync по умолчанию false для popen. Это означает, что команды буферизуются Ruby до тех пор, пока вы не вызовете pipe.close_write, pipe.close, не выйдете из программы или буфер не заполнится. Затем буфер очищается, предоставляя все буферизованные данные, записанные в другую программу.

Для получения дополнительной информации ознакомьтесь с документацией IO#sync и / или Что означает «file.syn» c = true ”делать?

На основании вашего комментария я не уверен, что понимаю вопрос. Единственная причина, по которой я могу придумать, почему pipe.gets(nil) вернет nil, заключается в том, что другая программа не имеет выходных данных.

Другая опция заключается в том, что pipe.gets(nil) будет блокироваться. Это может произойти, если pipe никогда не сбрасывается, что означает, что другая программа все еще ожидает ввода. Поскольку другая программа теперь блокирует и не закрыла, их стандартный вывод pipe.gets(nil) также будет блокировать. pipe.gets(nil) будет читать все со стандартного ввода. Откуда оно знает, что все прочитано? Он знает, потому что закрытое соединение означает, что не может быть никаких данных, поэтому он ожидает закрытое соединение.

Ruby                stdout -------> stdin    ./db
                    stdin <-------- stdout

                                             (blocked because empty)
pipe.puts("a")      "a\n"  -------> empty    <read from stdin>
                    empty <-------- empty

                                             (still blocked)
pipe.puts("b")      "a\nb\n" -----> empty    <read from stdin>
                    empty <-------- empty

(flushing stdout)                            (continues consuming "a\nb\n")
pipe.close_write    empty ----/---> "a\n\b"  <read from stdin>
                    empty <-------- empty

(blocks because empty)
pipe.gets(nil)      empty ----/---> empty    <send data to stdout>
                    empty <-------- "data\n"

(continues consuming "data\n")               (flushing stdout)
pipe.gets(nil)      empty ----/---> empty    <close stdout>
                    "data\n" <--/-- empty

Надеюсь, что выше помогает продемонстрировать процесс вашего текущего кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...