简体   繁体   English

为什么JRuby的read_nonblock块?

[英]Why does JRuby's read_nonblock block?

I'm trying to add error logging to a JRuby process that reads data from stdout of one subprocess, and writes this data to stdin of another subprocess, while collecting some statistics on the data. 我正在尝试将错误日志记录添加到JRuby进程,该进程从一个子进程的stdout读取数据,并将此数据写入另一个子进程的stdin,同时收集有关数据的一些统计信息。 The subprocesses are spawned using IO.popen4 . 使用IO.popen4生成子IO.popen4

To read the error streams, I can't use blocking reads because in the normal situation there is no output on those streams. 要读取错误流,我不能使用阻塞读取,因为在正常情况下,这些流上没有输出。 However, when I use read_nonblock on those streams, I still experience blocking reads in JRuby. 但是,当我在这些流上使用read_nonblock时,我仍然遇到JRuby中的阻塞读取。

Why do the read_nonblock calls block and how could I rewrite this code so it never blocks and always displays any stderr that either subprocess outputs? 为什么read_nonblock调用块,我怎么能重写这段代码,所以它永远不会阻塞并始终显示任何子进程输出的stderr?

Below is a simplified version of the code I'm using that reproduces the problem. 下面是我正在使用的代码的简化版本,可以重现问题。 It blocks on jruby and doesn't display the expected output on ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11.4.0] . 它在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

I know it is blocked in read_nonblock because of the stack trace when pressing ctrl+\\: 我知道它在read_nonblock中被阻塞,因为按下ctrl + \\时的堆栈跟踪:

"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)
...

So, this is a pretty offensive solution, but it's what worked for me. 所以,这是一个非常令人反感的解决方案,但它对我有用。 Since select always returns "yes", and nonblock just doesn't work, I don't see another choice: 由于select总是返回“yes”,而nonblock只是不起作用,我没有看到另一个选择:

      require 'timeout'
      begin
        while true
          line = nil
          Timeout::timeout(1) { line=io.gets }
          if line.nil?
            break
          else
            puts "line: #{line}"
          end
        end
      rescue Timeout::Error
      end

-Robin -Robin

(this isn't really an answer, more a continuation of the problem) (这不是一个真正的答案,更多的是问题的延续)

Mine never blocks (1.6.8) but always returns EAGAIN. 我从不阻止(1.6.8),但总是返回EAGAIN。 I have yet to find any way to detect-data-but-not-block with a pipe in jruby: 我还没有找到任何方法来检测数据但不阻塞jruby中的管道:

jruby-1.6.8 :001 > io=IO.popen('sh -c "sleep 10"') ; select([io],nil,nil,0)
 => [[#<IO:0x6e72d873>], [], []]
jruby-1.6.8 :003 > sleep 10 ; begin ; io.read_nonblock(1) ; rescue Exception => e ; puts "nothing: #{e.class.name}" ; puts "#{io.eof?}" ; end
nothing: Errno::EAGAIN
true
 => nil
jruby-1.6.8 :001 > io=IO.popen('sh -c "sleep 10"') ; select([io],nil,nil,0)
 => [[#<IO:0x6e72d873>], [], []]
jruby-1.6.8 :006 > require 'fcntl'; io=IO.popen('sh -c "sleep 10"') ; puts "f: #{io.fcntl(Fcntl::F_GETFL)}" ; io.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK) ; puts "f: #{io.fcntl(Fcntl::F_GETFL)}" ; puts "e: #{io.gets}"
f: 0
f: 0
e:
 => nil
jruby-1.6.8 :007 > io=IO.popen('sh -c "echo foo ; sleep 10"') ; select([io],nil,nil,0) ; begin ; io.read_nonblock(1) ; rescue Exception => e ; puts "nothing: #{e.class.name}" ;     puts "#{io.eof?}" ; end
nothing: Errno::EAGAIN
false
 => nil

Not that read_nonblock returns EAGAIN when data is present! 当数据存在时,read_nonblock不会返回EAGAIN! And at EOF! 在EOF! 0.o 0.o

-Robin -Robin

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在服务器/客户端上使用Ruby的write_nonblock / read_nonblock? - How to use Ruby's write_nonblock / read_nonblock with servers/clients? Ruby readpartial 和 read_nonblock 不抛出 EOFError - Ruby readpartial and read_nonblock not throwing EOFError Rake db操作在read_nonblock中获得EOF错误 - Rake db actions get an EOF error in read_nonblock HTTParty read_nonblock连接由对等Errno :: ECONNRESET重置 - HTTParty read_nonblock connection reset by peer Errno::ECONNRESET 如何使用read,readpartial和read_nonblock从ruby中的TCPServer套接字读取 - How to read from a TCPServer socket in ruby using read, readpartial and read_nonblock protocol.rb:153:在`read_nonblock&#39;中:到达文件末尾(EOFError) - protocol.rb:153:in `read_nonblock': end of file reached (EOFError) Ruby请求https - “in`read_nonblock&#39;:连接由peer重置(Errno :: ECONNRESET)” - Ruby request to https - “in `read_nonblock': Connection reset by peer (Errno::ECONNRESET)” s.recvfrom_nonblock(65536)[0]在此代码段中的作用 - What does s.recvfrom_nonblock(65536)[0] do in this code snippet 为什么JRuby不承认BigNums而Ruby呢? - Why does JRuby not recognize BigNums while Ruby does? 为什么sqlite 1.2.3 gem正确安装用于MRI但不适用于JRuby? - Why does the sqlite 1.2.3 gem install correctly for MRI but not for JRuby?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM