Ruby STDIN,阻塞与不阻塞
Ruby STDIN, blocking vs not blocking
我正在尝试查找有关如何在 Ruby 中处理 STDIN
的文档。
我试验过这个简单的脚本:
# test.rb
loop do
puts "stdin: #{$stdin.gets}"
sleep 2
end
我 运行 来自 bash(在 OS X 上):
$ ruby test.rb
正如我所料,对 $stdin.gets
的调用是阻塞的,循环等待下一个输入。 2 秒的休眠时间甚至允许我一次输入更多行,并且循环正确地按顺序打印它们,然后在清除 STDIN 时再次停止:
$ ruby test.rb
a
stdin: a
b
stdin: b
c
d
e
stdin: c
stdin: d
stdin: e
到目前为止,一切都很好。我期待着这一点。
然后,我用管道做了个测试:
$ mkfifo my_pipe
$ ruby test.rb < my_pipe
并且,在另一个 shell 中:
$ echo "Hello" > my_pipe
这一次,它的表现有点不同。
起初它确实等待,阻塞了循环。但是,在第一个输入通过管道后,它一直循环并打印空字符串:
$ ruby test.rb
stdin: Hello
stdin:
stdin:
stdin: Other input
stdin:
所以我的问题是:为什么不同?它是否将管道视为空文件?这在哪里记录? docs 没有说任何有关阻塞行为的信息,但他们确实是这样说的:
Returns nil if called at end of file.
这是一个开始。
所以简短的回答是肯定的,您正在从管道中获取 EOF。因为 echo 的工作方式是打开管道进行写入,写入,然后关闭(即发送 EOF)。然后对 echo 的新调用将重新打开它,读取它,然后关闭。
如果您改为使用一个在 3 秒睡眠后打印文件行的程序,您会看到您的应用程序将执行阻塞等待,直到该程序退出(此时永无止境的 EOF 将 return).
# slow_write.rb
ARGF.each do |line|
puts line
STDOUT.flush
sleep 3
end
我应该注意,此行为并非特定于 Ruby。 C stdlio 库具有完全相同的行为,并且由于大多数语言使用 C 基元作为其基础,因此它们也具有相同的行为。
我正在尝试查找有关如何在 Ruby 中处理 STDIN
的文档。
我试验过这个简单的脚本:
# test.rb
loop do
puts "stdin: #{$stdin.gets}"
sleep 2
end
我 运行 来自 bash(在 OS X 上):
$ ruby test.rb
正如我所料,对 $stdin.gets
的调用是阻塞的,循环等待下一个输入。 2 秒的休眠时间甚至允许我一次输入更多行,并且循环正确地按顺序打印它们,然后在清除 STDIN 时再次停止:
$ ruby test.rb
a
stdin: a
b
stdin: b
c
d
e
stdin: c
stdin: d
stdin: e
到目前为止,一切都很好。我期待着这一点。
然后,我用管道做了个测试:
$ mkfifo my_pipe
$ ruby test.rb < my_pipe
并且,在另一个 shell 中:
$ echo "Hello" > my_pipe
这一次,它的表现有点不同。
起初它确实等待,阻塞了循环。但是,在第一个输入通过管道后,它一直循环并打印空字符串:
$ ruby test.rb
stdin: Hello
stdin:
stdin:
stdin: Other input
stdin:
所以我的问题是:为什么不同?它是否将管道视为空文件?这在哪里记录? docs 没有说任何有关阻塞行为的信息,但他们确实是这样说的:
Returns nil if called at end of file.
这是一个开始。
所以简短的回答是肯定的,您正在从管道中获取 EOF。因为 echo 的工作方式是打开管道进行写入,写入,然后关闭(即发送 EOF)。然后对 echo 的新调用将重新打开它,读取它,然后关闭。
如果您改为使用一个在 3 秒睡眠后打印文件行的程序,您会看到您的应用程序将执行阻塞等待,直到该程序退出(此时永无止境的 EOF 将 return).
# slow_write.rb
ARGF.each do |line|
puts line
STDOUT.flush
sleep 3
end
我应该注意,此行为并非特定于 Ruby。 C stdlio 库具有完全相同的行为,并且由于大多数语言使用 C 基元作为其基础,因此它们也具有相同的行为。