How to print stdout immediately?

2019-04-19 11:34发布

问题:

How can I immediately output stdout? stdout is going to print after all input is complete.

require 'open3'
def run(cmd)
    Open3.popen3(cmd) do |stdin, stdout, stderr, thread|

    Thread.new do
      stdout.each {|l| puts l}
    end

    Thread.new do
      while thread.alive?
        stdin.puts $stdin.gets
      end
    end

    thread.join
  end
end

run ("ruby file_to_test.rb")

file_to_test.rb:

puts "please, enter s"
puts "please, enter q"

s = gets.chomp!
q = gets.chomp!

puts s
puts q

The result after running main.rb is:

somestring
somestring2
please, enter s
please, enter q
somestring
somestring2

How can I immediately output stdout?

回答1:

Ruby is buffering output until the output buffer is full. To change the behavior so it automatically writes use sync and sync=:

old_sync = $stdout.sync
$stdout.sync = true

puts "immediately output lotsa stuff"
puts "immediately output lotsa stuff"
puts "immediately output lotsa stuff"
puts "immediately output lotsa stuff"

# reenable the default behavior
$stdout.sync = old_sync

From the documentation for sync=:

Sets the “sync mode” to true or false. When sync mode is true, all output is immediately flushed to the underlying operating system and is not buffered internally.

It's important to understand that enabling automatic flushing of the buffer can actually slow the overall execution speed of your code, especially if you're writing to a file or device that wants to receive its data in chunks. Use sync or flushing carefully.



回答2:

Flush the output

What you are looking for is to flush the io stream by using the flush method.

Try the following after each iteration or each puts:

stdout.flush

If you had multiple puts in a row, I would suggest doing a flush after the last one, so you do not do it too often. Example:

stdout.puts "Hello"
stdout.puts "Mate"
stdout.flush