gpt4 book ai didi

Ruby 断管 @io_write -

转载 作者:太空宇宙 更新时间:2023-11-03 16:12:38 26 4
gpt4 key购买 nike

尝试运行 ruby​​ 程序并将输出通过管道传输到另一个程序时,如下所示:

ruby hello.rb | whoami

命令 whoami 按预期首先执行,但之后 hello.rb 崩溃:

Traceback (most recent call last):
2: from p.rb:2:in `<main>'
1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

只有当 STDOUT.sync 设置为 true 时才会发生这种情况

STDOUT.sync = true
STDOUT.print "Hello!"

[当通过管道传输到另一个程序时,在 STDOUT.puts 之后的 STDOUT.flush 会引发类似的错误]

这次崩溃背后的原因是什么?

最佳答案

简介

首先可以找到解释here .

无论如何,这是我的想法......

当这样使用管道时:

a | b

a和b都执行了concurrently . b 等待来自 a 的标准输入。

说到 Errno::EPIPELinux man page of write说:

EPIPE fd is connected to a pipe or socket whose reading end is closed. When this happens the writing process will also receive a SIGPIPE signal. (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.)

说到题目中的问题:当程序 whoami 运行时,它退出并且不再接受 ruby​​ 程序 hello.rb 发送的标准输入 - 导致管道损坏。

这里我写了 2 个 ruby​​ 程序,分别命名为 p.rb 和 q.rb 来测试:

  • p.rb
#!/usr/bin/env ruby
print ?* * 100_000
  • q.rb
#!/usr/bin/ruby
exit! 0

运行:

bash[~] $ ruby p.rb | ruby q.rb

Traceback (most recent call last):
2: from p.rb:2:in `<main>'
1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

让我们稍微修改一下q.rb的代码,让它接受输入:

#!/usr/bin/ruby -w
STDIN.gets

运行:

bash[~] $ ruby p.rb | ruby q.rb

是的,它实际上什么都不显示。原因是 q.rb 现在等待标准输入。 显然,在这里等待是最重要的。现在,即使使用 STDOUT.syncSTDOUT.flush 管道传输到此 q.rb,p.rb 也不会崩溃。

另一个例子:

  • p.rb
STDOUT.sync = true
loop until print("\e[2K<<<#{Time.now.strftime('%H:%M:%S:%2N')}>>>\r")

[警告:没有休眠的循环可能会提高你的 CPU 使用率]

  • q.rb
sleep 3

运行:

bash[~] $ time ruby p.rb | q.rb
Traceback (most recent call last):
2: from p.rb:2:in `<main>'
1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

real 0m3.186s
user 0m0.282s
sys 0m0.083s

您看到程序在 3 秒后崩溃了。如果 q.rb 有 sleep 5,它将在 5.1 秒后崩溃。类似地,q.rb 中的 sleep 0 将在 0.1 秒后崩溃 p.rb。我想额外的 0.1 秒取决于系统,因为我的系统需要 0.1 秒来加载 ruby​​ 解释器。

我写了 p.cr 和 q.cr Crystal 程序来测试。 Crystal 是compiled并且不需要 0.1 秒的长加载时间。

Crystal 程序:

  • p.cr
STDOUT.sync = true
loop do print("\e[2KHi!\r") end rescue exit
  • q.cr
sleep 3

我编译了它们,然后运行:

bash[~] $ time ./p | ./q

real 0m3.013s
user 0m0.007s
sys 0m0.019s

二进制文件 ./p 在非常接近 3 秒的时间内处理了 Unhandled exception: Error writing file: Broken pipe (Errno) 并退出。同样,两个 crystal 程序可能需要 0.01 秒来执行,也许内核也需要一点时间来运行这些进程。

还要注意 STDERR#printSTDERR#putsSTDERR#putcSTDERR#printfSTDERR#writeSTDERR#syswrite 即使输出同步也不会引发 Errno::EPIPE。

结论

管道是 arcane .将 STDOUT#sync 设置为 true 或使用 STDOUT#flush 将所有缓冲数据刷新到底层操作系统。

当运行 hello.rb | whoami,没有sync,我可以写入8191字节的数据,程序hello.rb不会崩溃。但是通过同步,通过管道写入 1 个字节将导致 hello.rb 崩溃。

因此,当 hello.rb 将标准输出与管道程序 whoami 同步时,whoami 不会等待 hello。 rb; hello.rb 引发 Errno::EPIPE 因为这两个程序之间的管道坏了(如果我在这里迷路了请纠正我)。

关于Ruby 断管 @io_write - <STDOUT>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58082748/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com