Ruby 为什么pipe.write会阻塞线程?
以下是示例程序:Ruby 为什么pipe.write会阻塞线程?,ruby,Ruby,以下是示例程序: from = File.open('test.bin', 'rb') to = IO.popen('cat', 'w+b') i = 0 while buff = from.read(4096) to.write(buff) # blocks here i += 1 print "#{i}, #{buff.size} bytes read \r" end 它读取二进制文件(您可以在Linux上使用fallocate-l 1MB te
from = File.open('test.bin', 'rb')
to = IO.popen('cat', 'w+b')
i = 0
while buff = from.read(4096)
to.write(buff) # blocks here
i += 1
print "#{i}, #{buff.size} bytes read \r"
end
它读取二进制文件(您可以在Linux上使用fallocate-l 1MB test.bin创建它),并将管道传输到cat
命令
但是,to.write(buff)
调用挂起。以下是它在控制台中的外观:
[1] pry(main)> from = File.open('test.bin', 'rb')
#<File:test.bin>
-rw-rw-r-- 1 admin admin 1000000 Mar 30 13:38 test.bin
[2] pry(main)> to = IO.popen('cat', 'w+b')
#<IO:fd 14>
[3] pry(main)> i = 0
0
[4] pry(main)>
[5] pry(main)> while buff = from.read(4096)
[5] pry(main)* to.write(buff)
[5] pry(main)* i += 1
[5] pry(main)* print "#{i}, #{buff.size} bytes read \r"
[5] pry(main)* end
33, 4096 bytes read
[1]pry(main)>from=File.open('test.bin','rb')
#
-rw-rw-r--1管理员1000000 3月30日13:38 test.bin
[2] 撬(主)>至=IO.popen('cat','w+b')
#
[3] 撬(主)>i=0
0
[4] 撬动(主)>
[5] 撬动(主)>而缓冲=从读取(4096)
[5] 撬动(主)*写入(buff)
[5] 撬(主)*i+=1
[5] pry(主)*打印“#{i},#{buff.size}字节读取\r”
[5] 撬(主)*端
读取334096字节
所以它只写135168字节。但是为什么呢
此外,如果我使用不同的命令(我需要它用于带有一些参数的gpg),字节数是不同的(大约60 MB),但结果是相同的,它在完全相同的点阻塞(这一点对于cat
和gpg
是不同的,对于每个程序来说,无论您运行程序多少次,它都是相同的)
环境:UbuntuLinux,ruby 2.3.4p301它之所以会阻塞,是因为IO.popen
打开了一个包含写入和读取文件句柄以及相关读写缓冲区的管道
由于您根本没有从io
对象的读取句柄读取数据,因此读取缓冲区最终会满(因为cat
不断地将其输入复制到输出),并且一旦读取缓冲区满了,操作系统就会阻塞管道的写入端,直到读取缓冲区中再次出现空间
你实际上造成了僵局
解决方案是保持从读取端读取,以防止读取缓冲区阻塞,或者不使命令输出任何内容
从读取句柄读取可能很棘手,因为它本身就是一个阻塞调用。您需要设置非阻塞读取,或者您可以使用单独的线程来执行读取
但是,最简单的解决方案是防止cat
输出任何内容,因此永远不会造成死锁情况:
to = IO.popen('cat > /dev/null', 'w+b')
这可能是你想要的,也可能不是,但它应该给你一些关于如何继续的想法