【问题标题】:ruby non-blocking line readruby 非阻塞行读取
【发布时间】:2014-10-07 01:30:57
【问题描述】:

我正在尝试以非阻塞方式从 io 读取一行。

不幸的是 readline 块。我想我可以使用read_nonblock 解决这个问题,并使用一个额外的缓冲区来存储部分结果,检查缓冲区中是否有多行等。但对于像这样的简单任务来说,这似乎有点复杂。有没有更好的方法来做到这一点?

注意:我正在使用事件多路分解 (select),对此我很满意,我不想创建线程、使用 EventMachine 等...

【问题讨论】:

    标签: ruby io nonblocking


    【解决方案1】:

    我认为 read_nonblock 解决方案可能是要走的路。简单但不是最有效的猴子补丁版本:

    class IO
      def readline_nonblock
        rlnb_buffer = ""
        while ch = self.read_nonblock(1) 
          rlnb_buffer << ch
          if ch == "\n" then
            result = rlnb_buffer
            return result
          end
        end     
      end
    end      
    

    如果没有准备好数据就会抛出异常,就像 read_nonblock 一样,所以你必须拯救它才能得到一个 nil 等。

    【讨论】:

    • 是的,这是我最初的想法,这就是我最终所做的,但我尽可能多地阅读(不仅仅是单个字符),我认为这对性能更好。感谢僧侣补丁提示;)
    【解决方案2】:

    此实现改进了 Mark Reed 的答案,不丢弃不以换行符结尾的读取数据:

    class IO
      def readline_nonblock
        buffer = ""
        buffer << read_nonblock(1) while buffer[-1] != "\n"
    
        buffer
      rescue IO::WaitReadable => blocking
        raise blocking if buffer.empty?
    
        buffer
      end
    end
    

    【讨论】:

    • “不保证”——这有点吓人。不要依赖未记录的“功能”。 “我测试了这个” - 彻底?用不同的输入法?它可能只是因为您的输入是行缓冲的...
    • 我也没有足够的勇气去依赖它,这就是我加入第二部分的原因。 :-)
    • 我验证了 read_nonblock(4096) 在 ruby​​ 1.9.3、2.0.0 和 2.1.3 上没有返回一行。最好把这个建议拿出来。很容易通过ruby19 -e 'x = IO.popen("cat /etc/fstab"); sleep 0.2; p x.read_nonblock(4096)' 进行验证。
    • 谢谢。编辑掉那个“不保证”的建议。
    • 那么编码呢?如果缓冲的输入在一个多字节字符序列的中间结束,然后在读取过程中 Ruby 进行了转码,然后我们将另一个从多字节字符序列的中间开始的转码块连接起来,会发生什么? Ruby IO 是否通过在内部缓冲外部编码中的部分最后一个字符然后将其添加到下一个块来防止这种情况发生?我在 Ruby 文档中找不到任何关于此的内容。
    猜你喜欢
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    • 2015-05-05
    • 2014-04-24
    • 2017-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多