Проще всего объяснить в коде:
require 'timeout'
puts "this block will properly kill the sleep after a second"
IO.popen("sleep 60") do |io|
begin
Timeout.timeout(1) do
while (line=io.gets) do
output += line
end
end
rescue Timeout::Error => ex
Process.kill 9, io.pid
puts "timed out: this block worked correctly"
end
end
puts "but this one blocks for >1 minute"
begin
pid = 0
Timeout.timeout(1) do
IO.popen("sleep 60") do |io|
pid = io.pid
while (line=io.gets) do
output += line
end
end
end
rescue Timeout::Error => ex
puts "timed out: the exception gets thrown, but much too late"
end
Моя ментальная модель двух блоков идентична:
Итак, что мне не хватает?
edit: drmaciver предложил в twitter, что в первом случае, по какой-то причине, сокет трубки переходит в неблокирующий режим, но во втором - нет. Я не могу придумать никаких причин, почему это произойдет, и я не могу понять, как получить флаги дескриптора, но это, по крайней мере, правдоподобный ответ? Работая над этой возможностью.