Есть ли простой способ проверки того, будет ли экземпляр ввода-вывода Ruby блокироваться при чтении()?

Я ищу метод в Ruby, который в основном таков:

io.ready_for_read?

Я просто хочу проверить, доступен ли данный объект IO (в моем случае, результат вызова popen), т.е. последующий вызов io.read(1) не будет блокироваться.

Это два варианта, которые я вижу, ни один из которых мне не нравится:

  • io.read_nonblock - слишком тонкая абстракция Unix read() - я не хочу иметь дело с обработкой ошибок errno.

  • io.select с таймаутом 0 - обманывает цель этой простой операции.

Есть ли лучшая альтернатива, которую я упустил?

Ответ 1

Немного поздно, но если вы require 'io/wait', вы можете использовать ready?, чтобы проверить, что IO может быть прочитан без блокировки. Конечно, в зависимости от того, насколько вы намерены читать (и как вы это планируете), ваш объект ввода-вывода все еще может блокироваться, но это должно помочь. Я не уверен, поддерживается ли эта библиотека на всех платформах, и я также не знаю, почему эта функциональность была отделена от остальной библиотеки IO. Подробнее здесь: http://ruby-doc.org/stdlib/libdoc/io/wait/rdoc/

Ответ 2

Я готов заключить, что нет, нет простого способа сделать это. По предложению Питера Купера здесь IO#ready_for_read?:

class IO
  def ready_for_read?
    result = IO.select([self], nil, nil, 0)
    result && (result.first.first == self)
  end
end

Ответ 3

В Windows я видел некоторые несоответствия с IO/wait. Рубин, который у меня есть сейчас:

ruby ​​1.9.2p136 (2010-12-25) [i386-mingw32]

В этом случае реализованы как nread, так и готовые?, но они возвращают ошибочные результаты. В другой версии, которую я использовал готов?, все еще был сломан и nread даже не существовал.

Одна из возможностей заключается в использовании io.stat.size, которая сообщает вам количество байтов, доступных для чтения в потоке ввода-вывода. http://www.ruby-doc.org/core/classes/File/Stat.html

Документация предполагает, что это для файлов, но я использовал ее на соединениях, подключенных к отдельному процессу (через Ruby Open3.popen3). Это действовало для меня до сих пор.