在文档中的Ruby IO.pipe
示例中,单个消息将通过这些进程传递。
我想做类似的事情,有两点不同:
这是显而易见但无效的代码:
rd, wr = IO.pipe
reader_thread = Thread.new(rd) do |rd|
data_received = rd.read
puts "Read: #{data_received.inspect}"
end
write_thread = Thread.new(wr) do |wr|
wr.write "Message"
wr.flush
end
write_thread.join
reader_thread.join
会导致reader_thread
挂起rd.read
。
我可以使用IO#read_nonblock
:
reader_thread = Thread.new(rd) do |rd|
data_received = \
begin
rd.read_nonblock(100)
rescue IO::WaitReadable, IO::EAGAINWaitReadable
IO.select([rd])
retry
end
puts "Read: #{data_received.inspect}"
end
这是正确的模式吗?或者使用IO.pipe
错误的工具进行线程消息传递?
答案 0 :(得分:0)
您还可以使用Queue
在多个线程之间安全地交换信息:
reset
set terminal pngcairo size 750,9.0 font ",10"
set output "parametric.png"
unset tics
unset border
set view equal xyz
set view ,,2
set view 100,30
set xyplane 0
set hidden3d
set parametric
set urange [0:2*pi]
set vrange [0:pi/2]
set style line 1 lc "red" lw 2
f(u,v) = cos(u)*cos(v)
g(u,v) = sin(u)*cos(v)
h(v) = sin(v)
set table $hemisphere
splot f(u,v), g(u,v), h(v)
unset table
set multiplot layout 4,2 columnsfirst
splot f(u,v), g(u,v), h(v) w l ls -1 t "Using functions (with ls -1 )"
splot f(u,v), g(u,v), h(v) w l lt 3 t "Using functions (with lt 3)"
splot f(u,v), g(u,v), h(v) w l ls 1 t "Using functions (with custom ls 1)"
splot f(u,v), g(u,v), h(v) w l lc "red" t "Using functions (with lc 'red')"
splot $hemisphere w l ls -1 t "Using datablock (with ls -1)"
splot $hemisphere w l lt 3 t "Using datablock (with lt 3)"
splot $hemisphere w l ls 1 t "Using datablock (with custom ls 1)"
splot $hemisphere w l lc "red" t "Using datablock (with lc 'red')"
unset multiplot
答案 1 :(得分:0)
您的读取器线程挂起,因为没有参数,IO.read
将读取 -- 并阻塞 -- 直到遇到 EOF。 (如果你传递一个 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 缓冲区或 even larger,具体取决于您的用例。
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.