我試圖將錯誤日誌記錄添加到從一個子進程的stdout中讀取數據的JRuby進程,並將此數據寫入另一個子進程的stdin,同時收集有關數據的一些統計信息。子流程使用IO.popen4
生成。爲什麼JRuby的read_nonblock塊?
要讀取錯誤流,我不能使用阻塞讀取,因爲在正常情況下,這些流上沒有輸出。但是,當我在這些流上使用時,我仍然在JRuby中遇到阻塞讀取。
爲什麼調用被阻止,我怎麼能重寫這段代碼,以便它永遠不會阻塞,並始終顯示任何子進程輸出的stderr?
下面是我使用的代碼的簡化版本,它重現了問題。它會阻止jruby,並且不會在ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11.4.0]
上顯示預期的輸出。
if RUBY_PLATFORM != "java" && RUBY_VERSION =~ /^1\.9/
class IO
def self.popen4(*args, &block)
require "open4"
Open4::popen4(*args, &block)
end
end
end
IO.popen4('echo', 'hi') do |_, _, stdout1, stderr1|
IO.popen4('sh', '-c', 'cat 1>&2') do |_, stdin2, _, stderr2|
stdout1.each_line do |line|
stdin2 << line
(IO.select([stderr1, stderr2], [], [], 0.1) or [[]]).first.each do |stream|
begin
# in jruby 1.6.8 (ruby-1.9.2-p312) (2012-09-18 1772b40) (Java HotSpot(TM) Client VM 1.6.0_37) [darwin-i386-java], read_nonblock blocks
# idem in jruby 1.7.2 (1.9.3p327) 2013-01-04 302c706 on Java HotSpot(TM) Client VM 1.6.0_37-b06-434-11M3909 [darwin-i386]
puts stream.read_nonblock(1000)
rescue Exception => e
puts e.message
end
end
end
end
end
我知道按CTRL當它被擋在read_nonblock因爲堆棧跟蹤+ \:
"main" prio=5 tid=0000000003110800 nid=0xb0201000 runnable [00000000b01ff000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.FileDispatcher.read0(Native Method)
at sun.nio.ch.FileDispatcher.read(FileDispatcher.java:26)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:198)
at sun.nio.ch.IOUtil.read(IOUtil.java:171)
at sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:144)
- locked <0000000006158308> (a java.lang.Object)
at org.jruby.util.io.ChannelStream.refillBuffer(ChannelStream.java:196)
at org.jruby.util.io.ChannelStream.bufferedRead(ChannelStream.java:926)
at org.jruby.util.io.ChannelStream.bufferedRead(ChannelStream.java:888)
at org.jruby.util.io.ChannelStream.fread(ChannelStream.java:1288)
- locked <000000000615a8f8> (a org.jruby.util.io.ChannelStream)
at org.jruby.util.io.ChannelStream.readnonblock(ChannelStream.java:1314)
- locked <000000000615a8f8> (a org.jruby.util.io.ChannelStream)
at org.jruby.RubyIO.getPartial(RubyIO.java:2762)
at org.jruby.RubyIO.read_nonblock(RubyIO.java:2697)
at org.jruby.RubyIO$INVOKER$i$0$1$read_nonblock.call(RubyIO$INVOKER$i$0$1$read_nonblock.gen)
at org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:646)
at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:204)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:168)
at read_nonblock_test.chained_2_rescue_1$RUBY$SYNTHETIC__file__(read_nonblock_test.rb:19)
at read_nonblock_test.block_3$RUBY$__file__(read_nonblock_test.rb:16)
at read_nonblock_test$block_3$RUBY$__file__.call(read_nonblock_test$block_3$RUBY$__file__)
at org.jruby.runtime.CompiledBlock19.yield(CompiledBlock19.java:139)
at org.jruby.runtime.Block.yield(Block.java:130)
...
礦塊(1.6.8),但*總是*返回EAGAIN。我還沒有找到*任何*的方式來檢測數據,但不是用jruby中的管道阻塞: – rlpowell
MRI不會阻塞嗎? – rogerdpack