您的阅读器线程挂起,因为没有参数,IO.read
将读取 - 并阻止 - 直到遇到 EOF。(如果您传递 a length
,它将一直读取,直到它读取那么多字节或 EOF,以先发生者为准,因此它仍然会阻塞,直到它至少获得那么多输入。)这在IO.pipe
docs中有详细说明。
如果你wd.close
之前打电话reader_thread.join
,read
会得到那个EOF,你会得到你的输出——所有的一次,当read
解除阻塞时。
在现实场景中,您可能不想只读取一次,您可能希望循环直到rd
遇到 EOF,沿途对数据进行处理。最简单的事情就是一次读取一个字节,使用read(1)
. (为了简单起见,我省略了单独的编写器线程——你也应该这样做,除非你真的需要三个单独的指令流;通常你会想要一个后台读取器线程或一个后台编写器线程,主线程处理另一端——但行为基本相同。
text = <<~TEXT.strip
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua.
TEXT
read_io, write_io = IO.pipe
reader_thread = Thread.new(read_io) do |io|
puts('Reading:')
while (c = io.read(1)) # block till we read one byte
$stdout.write(c)
end
puts('...Done.')
end
# Write 50 chars/second, so we can see them get read one at a time
text.chars.each { |c| write_io.write(c); sleep(0.02) }
reader_thread.join
# => Reading:
# Lorem ipsum dolor sit amet, consectetur adipiscing elit,
# sed do eiusmod tempor incididunt ut labore et dolore magna
# aliqua.
但是,这仍然挂起,因为IO.read(1)
仍在等待那个 EOF,所以再次,您需要关闭write_io
.
此外,逐字节读取通常效率不高。实际上,您可能需要8K缓冲区,甚至更大,具体取决于您的用例。
reader_thread = Thread.new(read_io) do |io|
puts('Reading:')
while (c = io.read(8192))
$stdout.write(c)
end
puts('...Done.')
end
# We're writing 50 chars/second, but we won't see them print out
# till `read_io` has read 8192 bytes, or hit an EOF
text.chars.each { |c| write_io.write(c); sleep(0.02) }
write_io.close # we have to close `write_io` *sometime* --
reader_thread.join # -- or this will hang.
# => Reading:
# Lorem ipsum dolor sit amet, consectetur adipiscing elit,
# sed do eiusmod tempor incididunt ut labore et dolore magna
# aliqua....Done.