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.
精彩评论