开发者

IO#select returns IO objects despite EOF -- is this expected?

I'm confused about how IO#select works in Ruby. I'm told here that it should only return the given IO objects if they are ready to 开发者_C百科be read. However, I'm getting IO objects returned even when eof? is true.

Am I missing something?

Here's some code that exhibits my confusion:

require 'open3'
stdin, stdout, stderr, thread = Open3.popen3('true')
eval_print = lambda {|code| puts "#{code} -> #{eval(code).inspect}" }
eval_print.call('stdout')
eval_print.call('stderr')
eval_print.call('select([stdout, stderr], nil, nil, 1)')
eval_print.call('stdout.eof?')
eval_print.call('stderr.eof?')
eval_print.call('stdout.gets')
eval_print.call('stderr.gets')
eval_print.call('select([stdout, stderr], nil, nil, 1)')

The output of this code (on Ruby version 1.9.2p136) is:

stdout -> #<IO:fd 5>
stderr -> #<IO:fd 7>
select([stdout, stderr], nil, nil, 1) -> [[#<IO:fd 5>, #<IO:fd 7>], [], []]
stdout.eof? -> true
stderr.eof? -> true
stdout.gets -> nil
stderr.gets -> nil
select([stdout, stderr], nil, nil, 1) -> [[#<IO:fd 5>, #<IO:fd 7>], [], []]

Shouldn't select return nil in both of those cases?


I don't blame you for being a little confused, the official docs are, shall we say, a little thin on what select is supposed to do.

IO.select is probably just a thin wrapper around the select system call so we'll have a look at that (which is quite well documented). From the Linux man pages:

Those listed in readfds will be watched to see if characters become available for reading (more precisely, to see if a read will not block; in particular, a file descriptor is also ready on end-of-file)

Emphasis mine. So, select is more about "will it block" than it is about "are there bytes waiting for me" and an EOF is a non-blocking state so select considers a file descriptor that is in an end-of-file condition to be ready for reading.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜